mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-05 18:44:27 +03:00
Demos: Import Fire demo contributed by "pd".
This commit is contained in:
parent
629501049f
commit
16f624421a
Notes:
sideshowbarker
2024-07-19 13:38:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/16f624421a4
BIN
Base/res/icons/16x16/app-demo.png
Normal file
BIN
Base/res/icons/16x16/app-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
3
Demos/Fire/.gitignore
vendored
Normal file
3
Demos/Fire/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Fire
|
||||
*.o
|
||||
*.d
|
236
Demos/Fire/Fire.cpp
Normal file
236
Demos/Fire/Fire.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/* Fire.cpp - a (classic) graphics demo for Serenity, by pd.
|
||||
* heavily based on the Fabien Sanglard's article:
|
||||
* http://fabiensanglard.net/doom_fire_psx/index.html
|
||||
*
|
||||
* Future directions:
|
||||
* [X] This does suggest the need for a palletized graphics surface. Thanks kling!
|
||||
* [X] alternate column updates, or vertical interlacing. this would certainly alter
|
||||
* the effect, but the update load would be halved.
|
||||
* [/] scaled blit
|
||||
* [ ] dithering?
|
||||
* [X] inlining rand()
|
||||
* [/] precalculating and recycling random data
|
||||
* [ ] rework/expand palette
|
||||
* [ ] switch to use tsc values for perf check
|
||||
* [ ] handle mouse events differently for smoother painting (queue)
|
||||
* [ ] handle fire bitmap edges better
|
||||
*/
|
||||
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GLabel.h>
|
||||
#include <LibGUI/GPainter.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define FIRE_WIDTH 320
|
||||
#define FIRE_HEIGHT 168
|
||||
#define FIRE_MAX 29
|
||||
|
||||
const Color palette[] = {
|
||||
Color(0x07, 0x07, 0x07), Color(0x1F, 0x07, 0x07), Color(0x2F, 0x0F, 0x07),
|
||||
Color(0x47, 0x0F, 0x07), Color(0x57, 0x17, 0x07), Color(0x67, 0x1F, 0x07),
|
||||
Color(0x77, 0x1F, 0x07), Color(0x9F, 0x2F, 0x07), Color(0xAF, 0x3F, 0x07),
|
||||
Color(0xBF, 0x47, 0x07), Color(0xC7, 0x47, 0x07), Color(0xDF, 0x4F, 0x07),
|
||||
Color(0xDF, 0x57, 0x07), Color(0xD7, 0x5F, 0x07), Color(0xD7, 0x5F, 0x07),
|
||||
Color(0xD7, 0x67, 0x0F), Color(0xCF, 0x6F, 0x0F), Color(0xCF, 0x7F, 0x0F),
|
||||
Color(0xCF, 0x87, 0x17), Color(0xC7, 0x87, 0x17), Color(0xC7, 0x8F, 0x17),
|
||||
Color(0xC7, 0x97, 0x1F), Color(0xBF, 0x9F, 0x1F), Color(0xBF, 0xA7, 0x27),
|
||||
Color(0xBF, 0xAF, 0x2F), Color(0xB7, 0xAF, 0x2F), Color(0xB7, 0xB7, 0x37),
|
||||
Color(0xCF, 0xCF, 0x6F), Color(0xEF, 0xEF, 0xC7), Color(0xFF, 0xFF, 0xFF)
|
||||
};
|
||||
|
||||
/* Random functions...
|
||||
* These are from musl libc's prng/rand.c
|
||||
*/
|
||||
static uint64_t seed;
|
||||
|
||||
void my_srand(unsigned s)
|
||||
{
|
||||
seed = s - 1;
|
||||
}
|
||||
|
||||
static int my_rand(void)
|
||||
{
|
||||
seed = 6364136223846793005ULL * seed + 1;
|
||||
return seed >> 33;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fire Widget
|
||||
*/
|
||||
class Fire : public GWidget {
|
||||
public:
|
||||
explicit Fire(GWidget* parent = nullptr);
|
||||
virtual ~Fire() override;
|
||||
void set_stat_label(GLabel* l) { stats = l; };
|
||||
|
||||
private:
|
||||
RetainPtr<GraphicsBitmap> bitmap;
|
||||
GLabel* stats;
|
||||
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
virtual void timer_event(CTimerEvent&) override;
|
||||
virtual void mousedown_event(GMouseEvent& event) override;
|
||||
virtual void mousemove_event(GMouseEvent& event) override;
|
||||
virtual void mouseup_event(GMouseEvent& event) override;
|
||||
|
||||
bool dragging;
|
||||
int timeAvg;
|
||||
int cycles;
|
||||
int phase;
|
||||
};
|
||||
|
||||
Fire::Fire(GWidget* parent)
|
||||
: GWidget(parent)
|
||||
{
|
||||
bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::Indexed8, { 320, 200 });
|
||||
|
||||
/* Initialize fire palette */
|
||||
for (int i = 0; i < 30; i++)
|
||||
bitmap->set_palette_color(i, palette[i]);
|
||||
|
||||
/* Set remaining entries to white */
|
||||
for (int i = 30; i < 256; i++)
|
||||
bitmap->set_palette_color(i, Color::White);
|
||||
|
||||
dragging = false;
|
||||
timeAvg = 0;
|
||||
cycles = 0;
|
||||
phase = 0;
|
||||
|
||||
my_srand(time(nullptr));
|
||||
stop_timer();
|
||||
start_timer(20);
|
||||
|
||||
/* Draw fire "source" on bottom row of pixels */
|
||||
for (int i = 0; i < FIRE_WIDTH; i++)
|
||||
bitmap->bits(bitmap->height() - 1)[i] = FIRE_MAX;
|
||||
|
||||
/* Set off initital paint event */
|
||||
//update();
|
||||
}
|
||||
|
||||
Fire::~Fire()
|
||||
{
|
||||
}
|
||||
|
||||
void Fire::paint_event(GPaintEvent& event)
|
||||
{
|
||||
CElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
GPainter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
|
||||
/* Blit it! */
|
||||
painter.draw_scaled_bitmap(event.rect(), *bitmap, bitmap->rect());
|
||||
|
||||
timeAvg += timer.elapsed();
|
||||
cycles++;
|
||||
}
|
||||
|
||||
void Fire::timer_event(CTimerEvent&)
|
||||
{
|
||||
/* Update only even or odd columns per frame... */
|
||||
phase++;
|
||||
if (phase > 1)
|
||||
phase = 0;
|
||||
|
||||
/* Paint our palettized buffer to screen */
|
||||
for (int px = 0 + phase; px < FIRE_WIDTH; px += 2) {
|
||||
for (int py = 1; py < 200; py++) {
|
||||
int rnd = my_rand() % 3;
|
||||
|
||||
/* Calculate new pixel value, don't go below 0 */
|
||||
byte nv = bitmap->bits(py)[px];
|
||||
if (nv > 0)
|
||||
nv -= (rnd & 1);
|
||||
|
||||
/* ...sigh... */
|
||||
int epx = px + (1 - rnd);
|
||||
if (epx < 0)
|
||||
epx = 0;
|
||||
else if (epx > FIRE_WIDTH)
|
||||
epx = FIRE_WIDTH;
|
||||
|
||||
bitmap->bits(py - 1)[epx] = nv;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cycles % 50) == 0) {
|
||||
dbgprintf("%d total cycles. finished 50 in %d ms, avg %d ms\n", cycles, timeAvg, timeAvg / 50);
|
||||
stats->set_text(String::format("%d ms", timeAvg / 50));
|
||||
timeAvg = 0;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Mouse handling events
|
||||
*/
|
||||
void Fire::mousedown_event(GMouseEvent& event)
|
||||
{
|
||||
if (event.button() == GMouseButton::Left)
|
||||
dragging = true;
|
||||
|
||||
return GWidget::mousedown_event(event);
|
||||
}
|
||||
|
||||
/* FIXME: needs to account for the size of the window rect */
|
||||
void Fire::mousemove_event(GMouseEvent& event)
|
||||
{
|
||||
if (dragging) {
|
||||
if (event.y() >= 2 && event.y() < 398 && event.x() <= 638) {
|
||||
int ypos = event.y() / 2;
|
||||
int xpos = event.x() / 2;
|
||||
bitmap->bits(ypos - 1)[xpos] = FIRE_MAX + 5;
|
||||
bitmap->bits(ypos - 1)[xpos + 1] = FIRE_MAX + 5;
|
||||
bitmap->bits(ypos)[xpos] = FIRE_MAX + 5;
|
||||
bitmap->bits(ypos)[xpos + 1] = FIRE_MAX + 5;
|
||||
}
|
||||
}
|
||||
|
||||
return GWidget::mousemove_event(event);
|
||||
}
|
||||
|
||||
void Fire::mouseup_event(GMouseEvent& event)
|
||||
{
|
||||
if (event.button() == GMouseButton::Left)
|
||||
dragging = false;
|
||||
|
||||
return GWidget::mouseup_event(event);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
GApplication app(argc, argv);
|
||||
|
||||
auto* window = new GWindow;
|
||||
window->set_should_exit_event_loop_on_close(true);
|
||||
window->set_double_buffering_enabled(false);
|
||||
window->set_title("Fire");
|
||||
window->set_resizable(false);
|
||||
window->set_rect(100, 100, 640, 400);
|
||||
|
||||
auto* fire = new Fire;
|
||||
window->set_main_widget(fire);
|
||||
|
||||
auto* time = new GLabel(fire);
|
||||
time->set_relative_rect({ 0, 4, 40, 10 });
|
||||
time->move_by({ window->width() - time->width(), 0 });
|
||||
time->set_foreground_color(Color::from_rgb(0x444444));
|
||||
fire->set_stat_label(time);
|
||||
|
||||
window->show();
|
||||
window->set_icon_path("/res/icons/16x16/app-demo.png");
|
||||
|
||||
return app.exec();
|
||||
}
|
22
Demos/Fire/Makefile
Normal file
22
Demos/Fire/Makefile
Normal file
@ -0,0 +1,22 @@
|
||||
include ../../Makefile.common
|
||||
|
||||
OBJS = \
|
||||
Fire.o
|
||||
|
||||
APP = Fire
|
||||
|
||||
DEFINES += -DUSERLAND
|
||||
|
||||
all: $(APP)
|
||||
|
||||
$(APP): $(OBJS)
|
||||
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
|
||||
clean:
|
||||
@echo "CLEAN"; rm -f $(APP) $(OBJS) *.d
|
||||
|
@ -75,6 +75,7 @@ cp ../Applications/PaintBrush/PaintBrush mnt/bin/PaintBrush
|
||||
cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld
|
||||
cp ../Demos/RetroFetch/RetroFetch mnt/bin/RetroFetch
|
||||
cp ../Demos/WidgetGallery/WidgetGallery mnt/bin/WidgetGallery
|
||||
cp ../Demos/Fire/Fire mnt/bin/Fire
|
||||
cp ../DevTools/VisualBuilder/VisualBuilder mnt/bin/VisualBuilder
|
||||
cp ../Games/Minesweeper/Minesweeper mnt/bin/Minesweeper
|
||||
cp ../Games/Snake/Snake mnt/bin/Snake
|
||||
|
@ -36,6 +36,7 @@ build_targets="$build_targets ../Shell"
|
||||
build_targets="$build_targets ../Demos/HelloWorld"
|
||||
build_targets="$build_targets ../Demos/RetroFetch"
|
||||
build_targets="$build_targets ../Demos/WidgetGallery"
|
||||
build_targets="$build_targets ../Demos/Fire"
|
||||
build_targets="$build_targets ." # the kernel
|
||||
|
||||
for targ in $build_targets; do
|
||||
|
Loading…
Reference in New Issue
Block a user