[GB.SDL2]

* NEW: Add the event loop, the framerate limitation, the Draw class.
* NEW: 'SDL2_image' will be used for image I/O instead of 'gb.image.io'.


git-svn-id: svn://localhost/gambas/trunk@6770 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Benoît Minisini 2014-12-27 08:33:25 +00:00
parent 6557ebfbc8
commit 7f06ab1316
9 changed files with 594 additions and 32 deletions

View file

@ -9,7 +9,7 @@ AC_PROG_LIBTOOL
GB_COMPONENT_SEARCH(
sdl2, SDL2, gb.sdl2, [src],
sdl2 ">= 2.0.2" SDL2_ttf ">= 2.0.12"
sdl2 ">= 2.0.2" SDL2_image ">= 2.0.0" SDL2_ttf ">= 2.0.12"
)
AC_OUTPUT( \

View file

@ -10,4 +10,5 @@ gb_sdl2_la_CPPFLAGS = @SDL2_INC@
gb_sdl2_la_SOURCES = \
c_window.h c_window.c \
c_draw.h c_draw.c \
main.h main.c

302
gb.sdl2/src/c_draw.c Normal file
View file

@ -0,0 +1,302 @@
/***************************************************************************
c_draw.c
(c) 2014 Benoît Minisini <gambas@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __C_DRAW_C
#include "c_window.h"
#include "c_draw.h"
#define DRAW_STACK_MAX 8
static CDRAW _draw_stack[DRAW_STACK_MAX];
static CDRAW *_draw_current = NULL;
#define THIS _draw_current
#define RENDERER _draw_current->renderer
static bool check_device(void)
{
if (THIS == NULL)
{
GB.Error("No device");
return TRUE;
}
else
return FALSE;
}
#define CHECK_DEVICE() if (check_device()) return
void DRAW_begin(void *device)
{
if (THIS >= &_draw_stack[DRAW_STACK_MAX - 1])
{
GB.Error("Too many nested drawings");
return;
}
if (GB.CheckObject(device))
return;
if (THIS == 0)
THIS = _draw_stack;
else
THIS++;
if (GB.Is(device, CLASS_Window))
{
THIS->device = device;
THIS->renderer = ((CWINDOW *)device)->renderer;
GB.Ref(THIS->device);
return;
}
GB.Error("Unsupported device");
}
void DRAW_end(void)
{
if (!THIS)
return;
SDL_RenderPresent(RENDERER);
GB.Unref(POINTER(&THIS->device));
THIS->device = NULL;
if (THIS == _draw_stack)
THIS = NULL;
else
THIS--;
}
//-------------------------------------------------------------------------
BEGIN_METHOD(Draw_Begin, GB_OBJECT device)
void *device = VARG(device);
DRAW_begin(device);
END_METHOD
BEGIN_METHOD_VOID(Draw_End)
DRAW_end();
END_METHOD
static GB_COLOR get_background()
{
uchar r, g, b, a;
SDL_GetRenderDrawColor(RENDERER, &r, &g, &b, &a);
return GB_COLOR_MAKE(r, g, b, a);
}
static void set_background(GB_COLOR col)
{
uchar r, g, b, a;
GB_COLOR_SPLIT(col, r, g, b, a);
SDL_SetRenderDrawColor(RENDERER, r, g, b, a);
if (a != 255)
SDL_SetRenderDrawBlendMode(RENDERER, SDL_BLENDMODE_BLEND);
else
SDL_SetRenderDrawBlendMode(RENDERER, SDL_BLENDMODE_NONE);
}
BEGIN_METHOD(Draw_Clear, GB_INTEGER col)
CHECK_DEVICE();
set_background(VARGOPT(col, 0));
SDL_RenderClear(RENDERER);
END_METHOD
BEGIN_PROPERTY(Draw_Background)
CHECK_DEVICE();
if (READ_PROPERTY)
GB.ReturnInteger(get_background());
else
set_background(VPROP(GB_INTEGER));
END_PROPERTY
BEGIN_METHOD(Draw_Rect, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h; GB_INTEGER col)
SDL_Rect rect;
CHECK_DEVICE();
rect.x = VARG(x);
rect.y = VARG(y);
rect.w = VARG(w);
rect.h = VARG(h);
set_background(VARG(col));
SDL_RenderDrawRect(RENDERER, &rect);
END_METHOD
BEGIN_METHOD(Draw_FillRect, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h; GB_INTEGER col)
SDL_Rect rect;
CHECK_DEVICE();
rect.x = VARG(x);
rect.y = VARG(y);
rect.w = VARG(w);
rect.h = VARG(h);
set_background(VARG(col));
SDL_RenderFillRect(RENDERER, &rect);
END_METHOD
BEGIN_METHOD(Draw_Line, GB_INTEGER x1; GB_INTEGER y1; GB_INTEGER x2; GB_INTEGER y2; GB_INTEGER col)
CHECK_DEVICE();
set_background(VARG(col));
SDL_RenderDrawLine(RENDERER, VARG(x1), VARG(y1), VARG(x2), VARG(y2));
END_METHOD
BEGIN_METHOD(Draw_Point, GB_INTEGER x; GB_INTEGER y; GB_INTEGER col)
CHECK_DEVICE();
set_background(VARG(col));
SDL_RenderDrawPoint(RENDERER, VARG(x), VARG(y));
END_METHOD
BEGIN_METHOD(Draw_Points, GB_OBJECT points; GB_INTEGER col)
GB_ARRAY points;
uint n;
CHECK_DEVICE();
points = (GB_ARRAY)VARG(points);
if (GB.CheckObject(points))
return;
n = GB.Array.Count(points) / 2;
if (n == 0)
return;
set_background(VARG(col));
SDL_RenderDrawPoints(RENDERER, (SDL_Point *)GB.Array.Get(points, 0), n);
END_METHOD
BEGIN_METHOD(Draw_Lines, GB_OBJECT points; GB_INTEGER col)
GB_ARRAY points;
uint n;
CHECK_DEVICE();
points = (GB_ARRAY)VARG(points);
if (GB.CheckObject(points))
return;
n = GB.Array.Count(points) / 2;
if (n == 0)
return;
set_background(VARG(col));
SDL_RenderDrawLines(RENDERER, (SDL_Point *)GB.Array.Get(points, 0), n);
END_METHOD
BEGIN_METHOD(Draw_Rects, GB_OBJECT rects; GB_INTEGER col)
GB_ARRAY rects;
uint n;
CHECK_DEVICE();
rects = (GB_ARRAY)VARG(rects);
if (GB.CheckObject(rects))
return;
n = GB.Array.Count(rects) / 4;
if (n == 0)
return;
set_background(VARG(col));
SDL_RenderDrawRects(RENDERER, (SDL_Rect *)GB.Array.Get(rects, 0), n);
END_METHOD
BEGIN_METHOD(Draw_FillRects, GB_OBJECT rects; GB_INTEGER col)
GB_ARRAY rects;
uint n;
CHECK_DEVICE();
rects = (GB_ARRAY)VARG(rects);
if (GB.CheckObject(rects))
return;
n = GB.Array.Count(rects) / 4;
if (n == 0)
return;
set_background(VARG(col));
SDL_RenderFillRects(RENDERER, (SDL_Rect *)GB.Array.Get(rects, 0), n);
END_METHOD
//-------------------------------------------------------------------------
GB_DESC DrawDesc[] =
{
GB_DECLARE_STATIC("Draw"),
GB_STATIC_METHOD("Begin", NULL, Draw_Begin, "(Device)o"),
GB_STATIC_METHOD("End", NULL, Draw_End, NULL),
GB_STATIC_METHOD("Clear", NULL, Draw_Clear, "[(Color)i]"),
GB_STATIC_METHOD("Rect", NULL, Draw_Rect, "(X)i(Y)i(Width)i(Height)i(Color)i"),
GB_STATIC_METHOD("Rects", NULL, Draw_Rects, "(Rectangles)Integer[];(Color)i"),
GB_STATIC_METHOD("FillRect", NULL, Draw_FillRect, "(X)i(Y)i(Width)i(Height)i(Color)i"),
GB_STATIC_METHOD("FillRects", NULL, Draw_FillRects, "(Rectangles)Integer[];(Color)i"),
GB_STATIC_METHOD("Line", NULL, Draw_Line, "(X1)i(Y1)i(X2)i(Y2)i(Color)i"),
GB_STATIC_METHOD("Lines", NULL, Draw_Lines, "(Lines)Integer[];(Color)i"),
GB_STATIC_METHOD("Point", NULL, Draw_Point, "(X)i(Y)i(Color)i"),
GB_STATIC_METHOD("Points", NULL, Draw_Points, "(Points)Integer[];(Color)i"),
GB_STATIC_PROPERTY("Background", "i", Draw_Background),
GB_END_DECLARE
};

46
gb.sdl2/src/c_draw.h Normal file
View file

@ -0,0 +1,46 @@
/***************************************************************************
c_draw.h
(c) 2014 Benoît Minisini <gambas@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#ifndef __C_DRAW_H
#define __C_DRAW_H
#include "main.h"
typedef
struct {
void *device;
SDL_Renderer *renderer;
}
CDRAW;
#ifndef __C_DRAW_C
extern GB_DESC DrawDesc[];
void DRAW_begin(void *device);
void DRAW_end();
#endif
#endif /* __C_DRAW_H */

View file

@ -23,6 +23,7 @@
#define __C_WINDOW_C
#include "c_draw.h"
#include "c_window.h"
#define THIS ((CWINDOW *)_object)
@ -38,9 +39,62 @@ DECLARE_EVENT(EVENT_Enter);
DECLARE_EVENT(EVENT_Leave);
DECLARE_EVENT(EVENT_GotFocus);
DECLARE_EVENT(EVENT_LostFocus);
DECLARE_EVENT(EVENT_Draw);
CWINDOW *WINDOW_list = NULL;
static void update_geometry(void *_object)
{
if (!THIS->opened)
return;
if (THIS->fullscreen)
{
SDL_SetWindowFullscreen(WINDOW, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_RenderSetLogicalSize(THIS->renderer, THIS->width, THIS->height);
}
else
{
SDL_SetWindowFullscreen(WINDOW, 0);
SDL_SetWindowPosition(WINDOW, THIS->x, THIS->y);
SDL_SetWindowSize(WINDOW, THIS->width, THIS->height);
}
}
static void open_window(void *_object)
{
if (THIS->opened)
return;
if (GB.Raise(THIS, EVENT_Open, 0))
return;
THIS->opened = TRUE;
GB.Ref(THIS);
LIST_insert(&WINDOW_list, THIS, &THIS->list);
SDL_ShowWindow(WINDOW);
update_geometry(THIS);
/*if (!THIS->opengl)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, this->GetWidth(), this->GetHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, GLdouble(this->GetWidth()), GLdouble(this->GetHeight()), 0.0f, -1, 1);
glMatrixMode(GL_MODELVIEW);
}*/
/*if (THIS->opengl)
{
if (GB.CanRaise(hWindow, EVENT_Resize))
GB.Raise(hWindow, EVENT_Resize,0);
}*/
}
static void close_window(void *_object)
{
if (!THIS->opened)
@ -75,9 +129,13 @@ void WINDOW_handle_event(SDL_WindowEvent *event)
break;
/*case SDL_WINDOWEVENT_EXPOSED:*/
case SDL_WINDOWEVENT_MOVED:
THIS->x = event->data1;
THIS->y = event->data2;
GB.Raise(THIS, EVENT_Move, 0);
break;
break;
case SDL_WINDOWEVENT_RESIZED:
THIS->width = event->data1;
THIS->height = event->data2;
GB.Raise(THIS, EVENT_Resize, 0);
break;
/*case SDL_WINDOWEVENT_MINIMIZED:
@ -107,13 +165,68 @@ void WINDOW_handle_event(SDL_WindowEvent *event)
}
}
void WINDOW_update(void)
{
CWINDOW *_object;
uint current_time;
uint diff;
bool at_least_one = FALSE;
current_time = SDL_GetTicks();
LIST_for_each(_object, WINDOW_list)
{
if (!GB.CanRaise(THIS, EVENT_Draw))
continue;
if (THIS->frame_time > 0)
{
double d = THIS->last_time + THIS->frame_time;
if (d > current_time)
continue;
THIS->last_time = d;
}
DRAW_begin(THIS);
GB.Raise(THIS, EVENT_Draw, 0);
DRAW_end();
//if (!cancel)
//SDL_RenderPresent(THIS->renderer);
//SDL_UpdateWindowSurface(WINDOW);
THIS->frame_count++;
THIS->total_frame_count++;
if (THIS->start_time == 0)
THIS->start_time = current_time;
else
{
diff = current_time - THIS->start_time;
if (diff > 1000)
{
THIS->frame_rate = THIS->frame_count;
THIS->frame_count = 0;
THIS->start_time += 1000;
}
}
at_least_one = TRUE;
}
if (!at_least_one)
SDL_Delay(1);
}
//-------------------------------------------------------------------------
BEGIN_METHOD(Window_new, GB_BOOLEAN opengl)
THIS->opengl = VARGOPT(opengl, FALSE);
THIS->fullscreen = FALSE;
THIS->width = 640;
THIS->height = 400;
if (SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_HIDDEN, &THIS->window, &THIS->renderer))
if (SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_HIDDEN, &THIS->window, &THIS->renderer))
{
RAISE_ERROR("Unable to create window");
return;
@ -132,16 +245,7 @@ END_METHOD
BEGIN_METHOD_VOID(Window_Show)
if (!THIS->opened)
{
if (GB.Raise(THIS, EVENT_Open, 0))
return;
THIS->opened = TRUE;
GB.Ref(THIS);
LIST_insert(&WINDOW_list, THIS, &THIS->list);
}
SDL_ShowWindow(WINDOW);
open_window(THIS);
END_METHOD
@ -164,37 +268,107 @@ BEGIN_PROPERTY(Window_Visible)
else
{
if (VPROP(GB_BOOLEAN))
SDL_ShowWindow(WINDOW);
open_window(THIS);
else
SDL_HideWindow(WINDOW);
}
END_PROPERTY
void set_geometry(void *_object, int x, int y, int w, int h)
{
if (x > 0 && y > 0)
SDL_SetWindowPosition(WINDOW, x, y);
if (w >= 0 && h >= 0)
{
SDL_SetWindowFullscreen(WINDOW, (w > 0 && h > 0) ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_SetWindowSize(WINDOW, w, h);
}
}
BEGIN_METHOD(Window_Move, GB_INTEGER x; GB_INTEGER y; GB_INTEGER width; GB_INTEGER height)
set_geometry(THIS, VARG(x), VARG(y), VARGOPT(width, -1), VARGOPT(height, -1));
int w = VARGOPT(width, -1);
int h = VARGOPT(height, -1);
THIS->x = VARG(x);
THIS->y = VARG(y);
if (w > 0) THIS->width = w;
if (h > 0) THIS->height = h;
update_geometry(THIS);
END_METHOD
BEGIN_METHOD(Window_Resize, GB_INTEGER width; GB_INTEGER height)
set_geometry(THIS, -1, -1, VARG(width), VARG(height));
int w = VARG(width);
int h = VARG(height);
if (w > 0) THIS->width = w;
if (h > 0) THIS->height = h;
update_geometry(THIS);
END_METHOD
BEGIN_PROPERTY(Window_X)
GB.ReturnInteger(THIS->x);
END_PROPERTY
BEGIN_PROPERTY(Window_Y)
GB.ReturnInteger(THIS->y);
END_PROPERTY
BEGIN_PROPERTY(Window_Width)
GB.ReturnInteger(THIS->width);
END_PROPERTY
BEGIN_PROPERTY(Window_Height)
GB.ReturnInteger(THIS->height);
END_PROPERTY
BEGIN_PROPERTY(Window_FullScreen)
if (READ_PROPERTY)
GB.ReturnBoolean(THIS->fullscreen);
else
{
THIS->fullscreen = VPROP(GB_BOOLEAN);
update_geometry(THIS);
}
END_PROPERTY
BEGIN_PROPERTY(Window_FrameRate)
if (READ_PROPERTY)
GB.ReturnFloat(THIS->frame_rate);
else
{
double val = VPROP(GB_FLOAT);
if (val < 0)
return;
THIS->frame_time = val ? 1000.0 / val : 0;
THIS->last_time = SDL_GetTicks();
}
END_PROPERTY
BEGIN_PROPERTY(Window_FrameCount)
GB.ReturnInteger(THIS->total_frame_count);
END_PROPERTY
BEGIN_PROPERTY(Window_Text)
if (READ_PROPERTY)
GB.ReturnNewZeroString(SDL_GetWindowTitle(WINDOW));
else
SDL_SetWindowTitle(WINDOW, GB.ToZeroString(PROP(GB_STRING)));
END_PROPERTY
//-------------------------------------------------------------------------
GB_DESC WindowDesc[] =
@ -211,6 +385,20 @@ GB_DESC WindowDesc[] =
GB_METHOD("Resize", NULL, Window_Resize, "(Width)i(Height)i"),
GB_PROPERTY("Visible", "b", Window_Visible),
GB_PROPERTY("FullScreen", "b", Window_FullScreen),
GB_PROPERTY_READ("X", "i", Window_X),
GB_PROPERTY_READ("Y", "i", Window_Y),
GB_PROPERTY_READ("W", "i", Window_Width),
GB_PROPERTY_READ("H", "i", Window_Height),
GB_PROPERTY_READ("Width", "i", Window_Width),
GB_PROPERTY_READ("Height", "i", Window_Height),
GB_PROPERTY("FrameRate", "f", Window_FrameRate),
GB_PROPERTY_READ("FrameCount", "i", Window_FrameCount),
GB_PROPERTY("Text", "s", Window_Text),
GB_PROPERTY("Title", "s", Window_Text),
GB_EVENT("Open", NULL, NULL, &EVENT_Open),
GB_EVENT("Close", NULL, NULL, &EVENT_Close),
@ -222,6 +410,7 @@ GB_DESC WindowDesc[] =
GB_EVENT("Leave", NULL, NULL, &EVENT_Leave),
GB_EVENT("GotFocus", NULL, NULL, &EVENT_GotFocus),
GB_EVENT("LostFocus", NULL, NULL, &EVENT_LostFocus),
GB_EVENT("Draw", NULL, NULL, &EVENT_Draw),
/* GB_METHOD("_new", NULL, CWINDOW_new, "[(OpenGL)b]"),
GB_METHOD("_free", NULL, CWINDOW_free, NULL),

View file

@ -32,8 +32,19 @@ typedef
LIST list;
SDL_Window *window;
SDL_Renderer *renderer;
bool opengl;
bool opened;
int x;
int y;
int width;
int height;
uint start_time;
uint frame_count;
uint total_frame_count;
double last_time;
double frame_time;
double frame_rate;
unsigned opengl : 1;
unsigned opened : 1;
unsigned fullscreen : 1;
}
CWINDOW;
@ -44,6 +55,7 @@ extern GB_DESC WindowDesc[];
extern CWINDOW *WINDOW_list;
void WINDOW_handle_event(SDL_WindowEvent *event);
void WINDOW_update();
#endif

View file

@ -1,5 +1,5 @@
[Component]
Key=gb.sdl2
Implements=EventLoop,OpenGLViewer
Requires=gb.image,gb.image.io
Implements=EventLoop,OpenGLViewer,ImageIO
Requires=gb.image
State=1

View file

@ -23,8 +23,11 @@
#define __MAIN_C
// Lazyfoo!
#include "gambas.h"
#include "main.h"
#include "c_draw.h"
#include "c_window.h"
#include "gb_list_temp.h"
@ -32,6 +35,8 @@
GB_INTERFACE GB EXPORT;
IMAGE_INTERFACE IMAGE EXPORT;
GB_CLASS CLASS_Window;
static void event_loop()
{
SDL_Event event;
@ -51,12 +56,16 @@ static void event_loop()
static void my_main(int *argc, char **argv)
{
CLASS_Window = GB.FindClass("Window");
}
static int my_loop()
{
while (WINDOW_list != NULL)
{
event_loop();
WINDOW_update();
}
return 1;
}
@ -68,6 +77,7 @@ static void my_wait(int duration)
GB_DESC *GB_CLASSES[] EXPORT =
{
DrawDesc,
WindowDesc,
NULL
};

View file

@ -30,10 +30,12 @@
#include "gb.image.h"
#include "SDL.h"
#include "SDL_opengl.h"
#ifndef __MAIN_C
extern GB_INTERFACE GB;
extern IMAGE_INTERFACE IMAGE;
extern GB_CLASS CLASS_Window;
#endif
#define RAISE_ERROR(_msg) GB.Error(_msg ": &1", SDL_GetError());