Pārlūkot izejas kodu

Properly implement program termination, including in the GTK program.

legacy
Sam Hocevar sam pirms 15 gadiem
vecāks
revīzija
d5ffa9fe4f
15 mainītis faili ar 186 papildinājumiem un 73 dzēšanām
  1. +2
    -0
      src/debugsprite.cpp
  2. +3
    -3
      src/dict.cpp
  3. +0
    -10
      src/entity.cpp
  4. +2
    -6
      src/entity.h
  5. +8
    -6
      src/font.cpp
  6. +14
    -3
      src/gtk/editor.cpp
  7. +6
    -6
      src/gtk/editor.xml
  8. +23
    -9
      src/gtk/glmapview.cpp
  9. +3
    -3
      src/gtk/glmapview.h
  10. +2
    -7
      src/sdlinput.cpp
  11. +1
    -1
      src/sdlinput.h
  12. +2
    -2
      src/test-map.cpp
  13. +107
    -11
      src/ticker.cpp
  14. +5
    -0
      src/ticker.h
  15. +8
    -6
      src/tileset.cpp

+ 2
- 0
src/debugsprite.cpp Parādīt failu

@@ -35,6 +35,7 @@ DebugSprite::DebugSprite(Game *game)
{
data = new DebugSpriteData();
data->game = game;
Ticker::Ref(game);
data->tiler = Tiler::Register("art/test/character-dress.png");
data->x = 320;
data->y = 206;
@@ -71,6 +72,7 @@ void DebugSprite::TickDraw(float deltams)

DebugSprite::~DebugSprite()
{
Ticker::Unref(data->game);
Tiler::Deregister(data->tiler);
delete data;
}


+ 3
- 3
src/dict.cpp Parādīt failu

@@ -85,7 +85,7 @@ int Dict::MakeSlot(char const *name)
}
else
{
data->entities[id]->Ref();
Ticker::Ref(data->entities[id]);
}

return id;
@@ -93,14 +93,14 @@ int Dict::MakeSlot(char const *name)

void Dict::RemoveSlot(int id)
{
if (data->entities[id]->Unref() == 0)
if (Ticker::Unref(data->entities[id]) == 0)
data->entities[id] = NULL;
}


void Dict::SetEntity(int id, Entity *entity)
{
entity->Ref();
Ticker::Ref(entity);
data->entities[id] = entity;
}



+ 0
- 10
src/entity.cpp Parādīt failu

@@ -63,13 +63,3 @@ void Entity::TickDraw(float deltams)
#endif
}

void Entity::Ref()
{
ref++;
}

int Entity::Unref()
{
return --ref;
}


+ 2
- 6
src/entity.h Parādīt failu

@@ -22,10 +22,6 @@ class Entity
friend class TickerData;
friend class Dict;

public:
virtual void Ref();
virtual int Unref();

protected:
typedef enum
{
@@ -47,8 +43,8 @@ protected:
virtual void TickGame(float deltams);
virtual void TickDraw(float deltams);

Entity *next;
int ref, destroy;
Entity *next, *autonext;
int ref, autorelease, destroy;

#if !FINAL_RELEASE
enum


+ 8
- 6
src/font.cpp Parādīt failu

@@ -74,7 +74,14 @@ void Font::TickDraw(float deltams)
{
Entity::TickDraw(deltams);

if (data->img)
if (destroy)
{
if (data->img)
SDL_FreeSurface(data->img);
else
glDeleteTextures(1, &data->texture);
}
else if (data->img)
{
data->width = data->img->w / 16;
data->height = data->img->h / 16;
@@ -91,11 +98,6 @@ void Font::TickDraw(float deltams)
SDL_FreeSurface(data->img);
data->img = NULL;
}
else if (ref == 0)
{
glDeleteTextures(1, &data->texture);
destroy = 1;
}
}

char const *Font::GetName()


+ 14
- 3
src/gtk/editor.cpp Parādīt failu

@@ -16,6 +16,15 @@
#include "glmapview.h"
#include "debugfps.h"

static gboolean delayed_quit(GtkWidget *w, GdkEvent *e, void *data)
{
(void)w;
(void)e;
(void)data;
gtk_main_quit();
return TRUE;
}

int main(int argc, char **argv)
{
/* Initialize GTK */
@@ -41,12 +50,14 @@ int main(int argc, char **argv)
GlMapView *glmapview = new GlMapView(builder);

/* Show window. We're good to go! */
gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(builder, "window")));
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
gtk_widget_show_all(window);
gtk_signal_connect(GTK_OBJECT(window), "delete_event",
GTK_SIGNAL_FUNC(delayed_quit), NULL);
g_object_unref(G_OBJECT(builder));

new DebugFps();
glmapview->LoadMap("maps/testmap.tmx");
glmapview->SetFocus();
new DebugFps();

gtk_main();



+ 6
- 6
src/gtk/editor.xml Parādīt failu

@@ -4,7 +4,6 @@
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Deus Hax Editor</property>
<signal name="delete_event" handler="gtk_main_quit"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
@@ -23,8 +22,8 @@
<child>
<object class="GtkImageMenuItem" id="imagemenuitem1">
<property name="visible">True</property>
<property name="related_action">action_new</property>
<property name="use_action_appearance">True</property>
<property name="related_action">action_new</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
@@ -32,8 +31,8 @@
<child>
<object class="GtkImageMenuItem" id="imagemenuitem2">
<property name="visible">True</property>
<property name="related_action">action_open</property>
<property name="use_action_appearance">True</property>
<property name="related_action">action_open</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
@@ -67,6 +66,7 @@
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="activate" handler="gtk_main_quit"/>
<signal name="activate" handler="gtk_true"/>
</object>
</child>
</object>
@@ -158,8 +158,8 @@
<child>
<object class="GtkToolButton" id="toolbutton2">
<property name="visible">True</property>
<property name="related_action">action_new</property>
<property name="use_action_appearance">True</property>
<property name="related_action">action_new</property>
<property name="label" translatable="yes">toolbutton</property>
<property name="use_underline">True</property>
</object>
@@ -171,8 +171,8 @@
<child>
<object class="GtkToolButton" id="toolbutton1">
<property name="visible">True</property>
<property name="related_action">action_open</property>
<property name="use_action_appearance">True</property>
<property name="related_action">action_open</property>
<property name="label" translatable="yes">Open...</property>
<property name="use_underline">True</property>
</object>
@@ -184,8 +184,8 @@
<child>
<object class="GtkToolButton" id="toolbutton4">
<property name="visible">True</property>
<property name="related_action">action_save</property>
<property name="use_action_appearance">True</property>
<property name="related_action">action_save</property>
<property name="label" translatable="yes">Save</property>
<property name="use_underline">True</property>
</object>


+ 23
- 9
src/gtk/glmapview.cpp Parādīt failu

@@ -50,11 +50,10 @@ GlMapView::GlMapView(GtkBuilder *builder)
* stealing time from the GTK loop when the callback time exceeds
* the timeout value. */
g_idle_add((GSourceFunc)IdleTickSignal, this);
gtk_quit_add(0, (GtkFunction)ShutdownSignal, this);

gtk_signal_connect(GTK_OBJECT(glarea), "realize",
GTK_SIGNAL_FUNC(SetupSignal), this);
gtk_signal_connect(GTK_OBJECT(glarea), "destroy",
GTK_SIGNAL_FUNC(DestroySignal), this);
gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
GTK_SIGNAL_FUNC(DrawSignal), this);
gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
@@ -75,17 +74,28 @@ void GlMapView::LoadMap(char const *path)
{
// FIXME: detect when the map viewer is killed
mapviewer = new MapViewer(path);
Ticker::Ref(mapviewer);

UpdateAdjustments();
}

void GlMapView::SetFocus()
void GlMapView::CloseMap()
{
gtk_widget_grab_focus(glarea);
if (mapviewer)
Ticker::Unref(mapviewer);
mapviewer = NULL;

UpdateAdjustments();
}

gboolean GlMapView::IdleTick()
{
if (Ticker::Finished())
{
gtk_main_quit();
return FALSE;
}

// FIXME: do not do anything if the previous tick was too recent?
ticking = TRUE;

@@ -104,6 +114,7 @@ gboolean GlMapView::IdleTick()
gboolean GlMapView::Setup()
{
/* Set up display */
gtk_widget_grab_focus(glarea);
if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
Video::Setup(glarea->allocation.width, glarea->allocation.height);

@@ -112,9 +123,13 @@ gboolean GlMapView::Setup()
return TRUE;
}

gboolean GlMapView::Destroy()
gboolean GlMapView::Shutdown()
{
g_idle_remove_by_data(this);
CloseMap();
Ticker::Shutdown();
/* Hijack the exit process by adding another level of gtk_main */
gtk_widget_set_sensitive(gtk_widget_get_toplevel(glarea), FALSE);
gtk_main();
return TRUE;
}

@@ -239,10 +254,9 @@ gboolean GlMapView::SetupSignal(GtkWidget *w, GlMapView *that)
return that->Setup();
}

gboolean GlMapView::DestroySignal(GtkWidget *w, GlMapView *that)
gboolean GlMapView::ShutdownSignal(GlMapView *that)
{
(void)w;
return that->Destroy();
return that->Shutdown();
}

gboolean GlMapView::DrawSignal(GtkWidget *w, GdkEventExpose *e,


+ 3
- 3
src/gtk/glmapview.h Parādīt failu

@@ -13,13 +13,13 @@ class GlMapView
public:
GlMapView(GtkBuilder *builder);
void LoadMap(char const *path);
void SetFocus();
void CloseMap();

private:
/* Private methods */
gboolean IdleTick();
gboolean Setup();
gboolean Destroy();
gboolean Shutdown();
gboolean Draw(GdkEventExpose *e);
void Scroll(double dx, double dy);
void UpdateAdjustments();
@@ -30,7 +30,7 @@ private:
/* Private signal slots */
static gboolean IdleTickSignal(GlMapView *that);
static gboolean SetupSignal(GtkWidget *w, GlMapView *that);
static gboolean DestroySignal(GtkWidget *w, GlMapView *that);
static gboolean ShutdownSignal(GlMapView *that);
static gboolean DrawSignal(GtkWidget *w, GdkEventExpose *e,
GlMapView *that);
static gboolean ReshapeSignal(GtkWidget *w, GdkEventConfigure *e,


+ 2
- 7
src/sdlinput.cpp Parādīt failu

@@ -21,7 +21,6 @@ class SdlInputData
friend class SdlInput;

private:
Game *game;
int mx, my;
};

@@ -29,12 +28,11 @@ private:
* Public SdlInput class
*/

SdlInput::SdlInput(Game *game)
SdlInput::SdlInput()
{
SDL_Init(SDL_INIT_TIMER);

data = new SdlInputData();
data->game = game;
SDL_GetMouseState(&data->mx, &data->my);
}

@@ -47,9 +45,6 @@ void SdlInput::TickGame(float deltams)
{
Entity::TickGame(deltams);

if (data->game->Finished())
destroy = 1;

/* Handle mouse input */
SDL_GetMouseState(&data->mx, &data->my);

@@ -58,7 +53,7 @@ void SdlInput::TickGame(float deltams)
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
data->game->Quit();
Ticker::Shutdown();
#if 0
else if (event.type == SDL_KEYDOWN)
Input::KeyPressed(event.key.keysym.sym, deltams);


+ 1
- 1
src/sdlinput.h Parādīt failu

@@ -19,7 +19,7 @@ class SdlInputData;
class SdlInput : public Entity
{
public:
SdlInput(Game *game);
SdlInput();
virtual ~SdlInput();

protected:


+ 2
- 2
src/test-map.cpp Parādīt failu

@@ -48,12 +48,12 @@ int main(int argc, char **argv)
Game *game = new Game("maps/testmap.tmx");

/* Register an input driver and some debug stuff */
new SdlInput(game);
new SdlInput();
new DebugFps();
new DebugSprite(game);
//new DebugRecord("lolengine.ogg");

while (!game->Finished())
while (!Ticker::Finished())
{
/* Tick the game */
Ticker::TickGame();


+ 107
- 11
src/ticker.cpp Parādīt failu

@@ -23,7 +23,8 @@ static class TickerData

public:
TickerData() :
todo(0), nentities(0),
todolist(0), autolist(0),
nentities(0),
frame(0), deltams(0), bias(0)
{
for (int i = 0; i < Entity::GROUP_COUNT; i++)
@@ -35,17 +36,26 @@ public:
#if !FINAL_RELEASE
if (nentities)
fprintf(stderr, "ERROR: still %i entities in ticker\n", nentities);
if (autolist)
{
int count = 0;
for (Entity *e = autolist; e; e = e->autonext, count++)
;
fprintf(stderr, "ERROR: still %i autoreleased entities\n", count);
}
fprintf(stderr, "INFO: %i frames required to quit\n",
frame - quitframe);
#endif
}

private:
/* Entity management */
Entity *todo;
Entity *todolist, *autolist;
Entity *list[Entity::GROUP_COUNT];
int nentities;

/* Fixed framerate management */
int frame;
int frame, quitframe;
Timer timer;
float deltams, bias;
}
@@ -62,8 +72,55 @@ void Ticker::Register(Entity *entity)
/* If we are called from its constructor, the object's vtable is not
* ready yet, so we do not know which group this entity belongs to. Wait
* until the first tick. */
entity->next = data->todo;
data->todo = entity;
entity->next = data->todolist;
data->todolist = entity;
/* Objects are autoreleased by default. Put them in a circular list. */
entity->autorelease = 1;
entity->autonext = data->autolist;
data->autolist = entity;
entity->ref = 1;

data->nentities++;
}

void Ticker::Ref(Entity *entity)
{
#if !FINAL_RELEASE
if (entity->destroy)
fprintf(stderr, "ERROR: refing entity scheduled for destruction\n");
#endif
if (entity->autorelease)
{
/* Get the entity out of the autorelease list. This is usually
* very fast since the first entry in autolist is the last
* registered entity. */
for (Entity *e = data->autolist, *prev = NULL; e;
prev = e, e = e->autonext)
{
if (e == entity)
{
if (prev)
prev->autonext = e->autonext;
else
data->autolist = e->autonext;
break;
}
}
entity->autorelease = 0;
}
else
entity->ref++;
}

int Ticker::Unref(Entity *entity)
{
#if !FINAL_RELEASE
if (entity->ref <= 0)
fprintf(stderr, "ERROR: dereferencing unreferenced entity\n");
if (entity->autorelease)
fprintf(stderr, "ERROR: dereferencing autoreleased entity\n");
#endif
return --entity->ref;
}

void Ticker::TickGame()
@@ -73,6 +130,17 @@ void Ticker::TickGame()

Profiler::Start(Profiler::STAT_TICK_GAME);

#if 0
fprintf(stderr, "-------------------------------------\n");
for (int i = 0; i < Entity::GROUP_COUNT; i++)
{
fprintf(stderr, "Group %i\n", i);

for (Entity *e = data->list[i]; e; e = e->next)
fprintf(stderr, " \\-- %s (ref %i, destroy %i)\n", e->GetName(), e->ref, e->destroy);
}
#endif

data->frame++;

data->deltams = data->timer.GetMs();
@@ -82,7 +150,8 @@ void Ticker::TickGame()
* before inserting awaiting objects, because there is no way these
* are already marked for destruction. */
for (int i = 0; i < Entity::GROUP_COUNT; i++)
for (Entity *e = data->list[i], *prev = NULL; e; prev = e, e = e->next)
for (Entity *e = data->list[i], *prev = NULL; e; )
{
if (e->destroy)
{
if (prev)
@@ -90,20 +159,30 @@ void Ticker::TickGame()
else
data->list[i] = e->next;

Entity *tmp = e;
e = e->next;
delete tmp;

data->nentities--;
delete e;
}
else
{
if (e->ref <= 0)
e->destroy = 1;
prev = e;
e = e->next;
}
}

/* Insert waiting objects into the appropriate lists */
while (data->todo)
while (data->todolist)
{
Entity *e = data->todo;
data->todo = e->next;
Entity *e = data->todolist;
data->todolist = e->next;

int i = e->GetGroup();
e->next = data->list[i];
data->list[i] = e;
data->nentities++;
}

/* Tick objects for the game loop */
@@ -169,3 +248,20 @@ int Ticker::GetFrameNum()
return data->frame;
}

void Ticker::Shutdown()
{
/* We're bailing out. Release all autorelease objects. */
while (data->autolist)
{
data->autolist->ref--;
data->autolist = data->autolist->autonext;
}

data->quitframe = data->frame;
}

int Ticker::Finished()
{
return !data->nentities;
}


+ 5
- 0
src/ticker.h Parādīt failu

@@ -20,11 +20,16 @@ class Ticker
{
public:
static void Register(Entity *entity);
static void Ref(Entity *entity);
static int Unref(Entity *entity);

static void TickGame();
static void TickDraw();
static void ClampFps(float deltams);
static int GetFrameNum();

static void Shutdown();
static int Finished();
};

#endif // __DH_TICKER_H__


+ 8
- 6
src/tileset.cpp Parādīt failu

@@ -83,7 +83,14 @@ void TileSet::TickDraw(float deltams)
{
Entity::TickDraw(deltams);

if (data->img)
if (destroy)
{
if (data->img)
SDL_FreeSurface(data->img);
else
glDeleteTextures(1, &data->texture);
}
else if (data->img)
{
glGenTextures(1, &data->texture);
glBindTexture(GL_TEXTURE_2D, data->texture);
@@ -97,11 +104,6 @@ void TileSet::TickDraw(float deltams)
SDL_FreeSurface(data->img);
data->img = NULL;
}
else if (ref == 0)
{
glDeleteTextures(1, &data->texture);
destroy = 1;
}
}

char const *TileSet::GetName()


Notiek ielāde…
Atcelt
Saglabāt