Bladeren bron

Properly implement program termination, including in the GTK program.

legacy
Sam Hocevar sam 15 jaren geleden
bovenliggende
commit
d5ffa9fe4f
15 gewijzigde bestanden met toevoegingen van 186 en 73 verwijderingen
  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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

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

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

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


+ 2
- 6
src/entity.h Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

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

protected:


+ 2
- 2
src/test-map.cpp Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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 Bestand weergeven

@@ -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()


Laden…
Annuleren
Opslaan