Migrate to SDL2 and deploy as WASM
All checks were successful
Build & deploy web version / Build WebAssembly & deploy (push) Successful in 1m8s
All checks were successful
Build & deploy web version / Build WebAssembly & deploy (push) Successful in 1m8s
This commit is contained in:
parent
81f4f20899
commit
c9b542eccf
6 changed files with 1411 additions and 483 deletions
|
|
@ -1,48 +1,208 @@
|
|||
#include "auxSDL.h"
|
||||
#include "../camera.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/html5.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
mousePos mouse; /**< Az egér koordinátáit tárolja, így egyszerűbb, mint közvetlen az eventek figyelése. */
|
||||
|
||||
static SDL_Window* window;
|
||||
static SDL_Renderer* renderer;
|
||||
static SDL_Texture* frameTexture;
|
||||
static int textureWidth, textureHeight;
|
||||
|
||||
/** \brief https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlcreatecursor.html
|
||||
* Hogy erre miért van szükség, az egy nagyon jó kérdés. Ha ehelyett a "SDL_ShowCursor(SDL_DISABLE);"-t
|
||||
* használnám az egér random ugrálna néha néha, így viszont ezt nem teszi.
|
||||
*/
|
||||
static SDL_Cursor* createCursor() {
|
||||
Uint8 data[4*32] = {0};
|
||||
Uint8 mask[4*32] = {0};
|
||||
return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
///A böngésző pixelarányát adja vissza, a szoftveres rajzolás miatt megszabott plafonig.
|
||||
static double drawingPixelRatio() {
|
||||
double ratio = emscripten_get_device_pixel_ratio();
|
||||
return ratio > maxDevicePixelRatio ? maxDevicePixelRatio : ratio;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void moveToResourceDirectory() {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
char* base = SDL_GetBasePath();
|
||||
if(base != NULL) {
|
||||
if(chdir(base) != 0) fprintf(stderr, "Nem sikerult a munkakonyvtar valtas!\n");
|
||||
SDL_free(base);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
|
||||
* Megnézi az elérhető legnagyobb felbontást, azzal a felbontással létrehoz egy ablakot, illetve
|
||||
* meghív pár, az inicializáláshoz szükséges függvényt.
|
||||
* \return kurzor amit fel kell később szabadítanunk
|
||||
/** \brief Gondoskodik róla, hogy a textúra legalább a kért méretű legyen.
|
||||
* Böngészőben a textúra eldobása átméretezéskor elveszejti a webgl kontextust, ezért
|
||||
* a textúrát egyszer, jó bőre foglaljuk, és utána már csak egy részét használjuk.
|
||||
*/
|
||||
SDL_Cursor* openWindow() {
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
||||
SDL_Rect** screenSizes = SDL_ListModes(NULL, SDL_FULLSCREEN);
|
||||
static void ensureTexture(int width, int height) {
|
||||
if(frameTexture != NULL && width <= textureWidth && height <= textureHeight) return;
|
||||
|
||||
screen = SDL_SetVideoMode(screenSizes[0] -> w, screenSizes[0] -> h, 0, SDL_FULLSCREEN);
|
||||
if(width > textureWidth) textureWidth = width;
|
||||
if(height > textureHeight) textureHeight = height;
|
||||
|
||||
if (!screen) {
|
||||
fprintf(stderr, "Nem sikerult megnyitni az ablakot!\n");
|
||||
SDL_DestroyTexture(frameTexture);
|
||||
frameTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||
SDL_TEXTUREACCESS_STREAMING, textureWidth, textureHeight);
|
||||
|
||||
if(frameTexture == NULL) {
|
||||
fprintf(stderr, "Nem sikerult letrehozni a texturat: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief A megadott méretű rajzfelületet hozza létre a régi helyére.
|
||||
* A rajzfelület mindig pontosan akkora, mint a megjelenítő felülete, így nincs se
|
||||
* fekete csík, se átméretezés.
|
||||
*/
|
||||
static void createDrawingSurface(int width, int height) {
|
||||
if(width < 1) width = 1;
|
||||
if(height < 1) height = 1;
|
||||
|
||||
ensureTexture(width, height);
|
||||
|
||||
SDL_FreeSurface(screen);
|
||||
screen = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||
|
||||
if(screen == NULL) {
|
||||
fprintf(stderr, "Nem sikerult letrehozni a rajzfeluletet: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_WM_SetCaption("Platform játék", "Schmelczer András: Platform játék");
|
||||
SDL_Cursor* cursor = createCursor();
|
||||
SDL_SetCursor(cursor);
|
||||
openFonts();
|
||||
SDL_WM_GrabInput(SDL_GRAB_FULLSCREEN);
|
||||
return cursor;
|
||||
SDL_RenderSetLogicalSize(renderer, width, height);
|
||||
}
|
||||
|
||||
///A játék időzítéséhez szükséges.
|
||||
Uint32 timer(Uint32 ms, void* param) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_USEREVENT;
|
||||
SDL_PushEvent(&event);
|
||||
return ms;
|
||||
/** \brief Az ablak méretének változását követi le, képkockánként meghívva.
|
||||
* Böngészőben a vászon css-méretéhez igazítja az ablakot, majd ha kell, új rajzfelületet
|
||||
* készít, a betűtípusokat a magassághoz igazítja, és a kamerával újraszámoltatja,
|
||||
* hogy mennyi látszik a pályából.
|
||||
*/
|
||||
void handleResize() {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
double cssWidth, cssHeight;
|
||||
if(emscripten_get_element_css_size("#canvas", &cssWidth, &cssHeight) == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
double ratio = drawingPixelRatio();
|
||||
int wantedWidth = (int)(cssWidth * ratio);
|
||||
int wantedHeight = (int)(cssHeight * ratio);
|
||||
|
||||
int currentWidth, currentHeight;
|
||||
SDL_GetWindowSize(window, ¤tWidth, ¤tHeight);
|
||||
|
||||
if(wantedWidth > 0 && wantedHeight > 0 && (wantedWidth != currentWidth || wantedHeight != currentHeight))
|
||||
SDL_SetWindowSize(window, wantedWidth, wantedHeight);
|
||||
}
|
||||
#endif
|
||||
|
||||
int outputWidth, outputHeight;
|
||||
SDL_GetRendererOutputSize(renderer, &outputWidth, &outputHeight);
|
||||
|
||||
if(screen != NULL && screen -> w == outputWidth && screen -> h == outputHeight) return;
|
||||
|
||||
bool heightChanged = screen == NULL || screen -> h != outputHeight;
|
||||
createDrawingSurface(outputWidth, outputHeight);
|
||||
|
||||
if(heightChanged) {
|
||||
freeFonts();
|
||||
openFonts();
|
||||
}
|
||||
|
||||
refreshCameraForScreen();
|
||||
}
|
||||
|
||||
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
|
||||
* Létrehoz egy ablakot a hozzá tartozó rajzfelülettel, illetve
|
||||
* meghív pár, az inicializáláshoz szükséges függvényt.
|
||||
*/
|
||||
void openWindow() {
|
||||
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
fprintf(stderr, "Nem sikerult inicializalni az SDL-t: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
moveToResourceDirectory();
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
|
||||
int windowWidth = defaultWindowWidth;
|
||||
int windowHeight = defaultWindowHeight;
|
||||
Uint32 windowFlags = 0;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
double cssWidth, cssHeight;
|
||||
if(emscripten_get_element_css_size("#canvas", &cssWidth, &cssHeight) == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
double ratio = drawingPixelRatio();
|
||||
windowWidth = (int) (cssWidth * ratio);
|
||||
windowHeight = (int) (cssHeight * ratio);
|
||||
}
|
||||
#else
|
||||
windowFlags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
SDL_Rect usableBounds;
|
||||
if(SDL_GetDisplayUsableBounds(0, &usableBounds) == 0) {
|
||||
float fit = smallerF((float) usableBounds.w / defaultWindowWidth, (float) usableBounds.h / defaultWindowHeight);
|
||||
if(fit < 1.0f) {
|
||||
windowWidth = (int) (defaultWindowWidth * fit);
|
||||
windowHeight = (int) (defaultWindowHeight * fit);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* forcedSize = SDL_getenv("GAME_WINDOW");
|
||||
if(forcedSize != NULL) sscanf(forcedSize, "%dx%d", &windowWidth, &windowHeight);
|
||||
|
||||
window = SDL_CreateWindow("Platform játék",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
windowWidth, windowHeight,
|
||||
windowFlags);
|
||||
|
||||
if(window == NULL) {
|
||||
fprintf(stderr, "Nem sikerult megnyitni az ablakot: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if(renderer == NULL) renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if(renderer == NULL) {
|
||||
fprintf(stderr, "Nem sikerult letrehozni a renderert: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
int screenPixelWidth, screenPixelHeight;
|
||||
emscripten_get_screen_size(&screenPixelWidth, &screenPixelHeight);
|
||||
double screenRatio = drawingPixelRatio();
|
||||
textureWidth = (int)(screenPixelWidth * screenRatio);
|
||||
textureHeight = (int)(screenPixelHeight * screenRatio);
|
||||
#else
|
||||
SDL_DisplayMode desktop;
|
||||
if(SDL_GetDesktopDisplayMode(0, &desktop) == 0) {
|
||||
textureWidth = desktop.w;
|
||||
textureHeight = desktop.h;
|
||||
}
|
||||
#endif
|
||||
|
||||
int outputWidth, outputHeight;
|
||||
SDL_GetRendererOutputSize(renderer, &outputWidth, &outputHeight);
|
||||
createDrawingSurface(outputWidth, outputHeight);
|
||||
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
openFonts();
|
||||
}
|
||||
|
||||
void presentFrame() {
|
||||
SDL_Rect used = {0, 0, screen -> w, screen -> h};
|
||||
SDL_UpdateTexture(frameTexture, &used, screen -> pixels, screen -> pitch);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, frameTexture, &used, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
void closeWindow() {
|
||||
SDL_FreeSurface(screen);
|
||||
SDL_DestroyTexture(frameTexture);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
///Frissití az egér pozicióját.
|
||||
|
|
@ -58,10 +218,11 @@ mousePos getMousePosition() {
|
|||
|
||||
///Lerajzolja a képernyőre az egeret, erre azért van szükség, mert az SDL csak fekete-fehér egérmutatót kezel.
|
||||
void drawMouse(bool isBW) {
|
||||
Sint16 x1 = mouse.x - mouseSize / 2;
|
||||
Sint16 x2 = mouse.x + mouseSize / 2;
|
||||
Sint16 y1 = mouse.y - mouseSize / 2;
|
||||
Sint16 y2 = mouse.y + mouseSize / 2;
|
||||
Sint16 size = larger(4, mouseSize * screen -> h / designHeight);
|
||||
Sint16 x1 = mouse.x - size / 2;
|
||||
Sint16 x2 = mouse.x + size / 2;
|
||||
Sint16 y1 = mouse.y - size / 2;
|
||||
Sint16 y2 = mouse.y + size / 2;
|
||||
boxColor(screen, x1, y1, x2, y2, isBW ? 0x7F7F7FFF : 0xFFFF00FF);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,24 @@
|
|||
|
||||
#define mouseSize 20 /**< Az egérmutató négyzetnek az oldalhosszusága. */
|
||||
|
||||
#define defaultWindowWidth 1920 /**< Az ablak alapértelmezett szélessége. */
|
||||
#define defaultWindowHeight 1080 /**< Az ablak alapértelmezett magassága. */
|
||||
|
||||
/** \brief Böngészőben legfeljebb ennyi rajzfelület-pixel jusson egy css-pixelre.
|
||||
* A teljes képet a processzor rajzolja, így a költsége a pixelek számával nő. Egy retina
|
||||
* kijelzőn a natív felbontás négyszer annyi pixelt jelentene; helyette css-méretben rajzolunk,
|
||||
* a vásznat pedig a böngésző nagyítja fel, ami már ingyen van.
|
||||
*/
|
||||
#define maxDevicePixelRatio 1.0
|
||||
|
||||
typedef struct mousePos {
|
||||
Uint16 x, y;
|
||||
} mousePos;
|
||||
|
||||
SDL_Cursor* openWindow();
|
||||
Uint32 timer(Uint32 ms, void* param);
|
||||
void openWindow();
|
||||
void handleResize();
|
||||
void presentFrame();
|
||||
void closeWindow();
|
||||
void setMousePosition(Uint16 x, Uint16 y);
|
||||
mousePos getMousePosition();
|
||||
void drawMouse(bool isBW);
|
||||
|
|
|
|||
300
Forráskód/modules/auxiliary/gfxPrimitives.c
Normal file
300
Forráskód/modules/auxiliary/gfxPrimitives.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
#include "gfxPrimitives.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct target {
|
||||
SDL_Surface* surface;
|
||||
Uint32* pixels;
|
||||
int pitch, w, h;
|
||||
int rShift, gShift, bShift;
|
||||
Uint32 aMask;
|
||||
bool locked;
|
||||
} target;
|
||||
|
||||
static bool renderingEnabled = true; /**< Kikapcsolva minden rajzoló primitív azonnal visszatér. */
|
||||
|
||||
/** \brief Ki-be kapcsolja a rajzolást.
|
||||
* A behozott képkockákat a main.c "utolérő" ciklusa többször is végigszimulálja, de csak
|
||||
* az utolsót mutatja meg. A közbülső lépések alatt kikapcsolva a rajzolás nem dolgozik feleslegesen.
|
||||
*/
|
||||
void setRenderingEnabled(bool enabled) {
|
||||
renderingEnabled = enabled;
|
||||
}
|
||||
|
||||
bool isRenderingEnabled() {
|
||||
return renderingEnabled;
|
||||
}
|
||||
|
||||
static bool beginTarget(SDL_Surface* dst, target* t) {
|
||||
if(!renderingEnabled || dst == NULL || dst -> format -> BytesPerPixel != 4) return false;
|
||||
|
||||
t -> surface = dst;
|
||||
t -> locked = SDL_MUSTLOCK(dst);
|
||||
if(t -> locked && SDL_LockSurface(dst) != 0) return false;
|
||||
|
||||
t -> pixels = (Uint32*) dst -> pixels;
|
||||
t -> pitch = dst -> pitch / 4;
|
||||
t -> w = dst -> w;
|
||||
t -> h = dst -> h;
|
||||
t -> rShift = dst -> format -> Rshift;
|
||||
t -> gShift = dst -> format -> Gshift;
|
||||
t -> bShift = dst -> format -> Bshift;
|
||||
t -> aMask = dst -> format -> Amask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void endTarget(target* t) {
|
||||
if(t -> locked) SDL_UnlockSurface(t -> surface);
|
||||
}
|
||||
|
||||
static inline Uint32 packColor(const target* t, Uint8 r, Uint8 g, Uint8 b) {
|
||||
return t -> aMask | ((Uint32) r << t -> rShift) | ((Uint32) g << t -> gShift) | ((Uint32) b << t -> bShift);
|
||||
}
|
||||
|
||||
static inline void blendPixel(const target* t, int x, int y, Uint8 r, Uint8 g, Uint8 b, int a) {
|
||||
if(a <= 0 || x < 0 || y < 0 || x >= t -> w || y >= t -> h) return;
|
||||
|
||||
Uint32* p = t -> pixels + y * t -> pitch + x;
|
||||
|
||||
if(a >= 255) {
|
||||
*p = packColor(t, r, g, b);
|
||||
return;
|
||||
}
|
||||
|
||||
Uint32 c = *p;
|
||||
int ia = 255 - a;
|
||||
Uint32 dr = (c >> t -> rShift) & 0xFF;
|
||||
Uint32 dg = (c >> t -> gShift) & 0xFF;
|
||||
Uint32 db = (c >> t -> bShift) & 0xFF;
|
||||
|
||||
*p = packColor(t,
|
||||
(Uint8) ((r * a + dr * ia + 127) / 255),
|
||||
(Uint8) ((g * a + dg * ia + 127) / 255),
|
||||
(Uint8) ((b * a + db * ia + 127) / 255));
|
||||
}
|
||||
|
||||
static void blendHLine(const target* t, int xa, int xb, int y, Uint8 r, Uint8 g, Uint8 b, int a) {
|
||||
if(y < 0 || y >= t -> h || a <= 0) return;
|
||||
if(xa > xb) { int tmp = xa; xa = xb; xb = tmp; }
|
||||
if(xa < 0) xa = 0;
|
||||
if(xb > t -> w - 1) xb = t -> w - 1;
|
||||
if(xa > xb) return;
|
||||
|
||||
Uint32* p = t -> pixels + y * t -> pitch + xa;
|
||||
int i;
|
||||
|
||||
if(a >= 255) {
|
||||
Uint32 c = packColor(t, r, g, b);
|
||||
for(i = xa; i <= xb; i++) *p++ = c;
|
||||
}
|
||||
else {
|
||||
int ia = 255 - a;
|
||||
int ra = r * a, ga = g * a, ba = b * a;
|
||||
|
||||
for(i = xa; i <= xb; i++, p++) {
|
||||
Uint32 c = *p;
|
||||
*p = packColor(t,
|
||||
(Uint8) ((ra + ((c >> t -> rShift) & 0xFF) * ia + 127) / 255),
|
||||
(Uint8) ((ga + ((c >> t -> gShift) & 0xFF) * ia + 127) / 255),
|
||||
(Uint8) ((ba + ((c >> t -> bShift) & 0xFF) * ia + 127) / 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void unpackColor(Uint32 color, Uint8* r, Uint8* g, Uint8* b, Uint8* a) {
|
||||
*r = (color >> 24) & 0xFF;
|
||||
*g = (color >> 16) & 0xFF;
|
||||
*b = (color >> 8) & 0xFF;
|
||||
*a = color & 0xFF;
|
||||
}
|
||||
|
||||
int boxRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
if(x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; }
|
||||
if(y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; }
|
||||
|
||||
int yStart = y1 < 0 ? 0 : y1;
|
||||
int yEnd = y2 > t.h - 1 ? t.h - 1 : y2;
|
||||
|
||||
int y;
|
||||
for(y = yStart; y <= yEnd; y++) blendHLine(&t, x1, x2, y, r, g, b, a);
|
||||
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int boxColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
|
||||
Uint8 r, g, b, a;
|
||||
unpackColor(color, &r, &g, &b, &a);
|
||||
return boxRGBA(dst, x1, y1, x2, y2, r, g, b, a);
|
||||
}
|
||||
|
||||
static int lineRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
int dx = abs(x2 - x1), dy = -abs(y2 - y1);
|
||||
int sx = x1 < x2 ? 1 : -1, sy = y1 < y2 ? 1 : -1;
|
||||
int err = dx + dy;
|
||||
int x = x1, y = y1;
|
||||
|
||||
while(true) {
|
||||
blendPixel(&t, x, y, r, g, b, a);
|
||||
if(x == x2 && y == y2) break;
|
||||
int e2 = 2 * err;
|
||||
if(e2 >= dy) { err += dy; x += sx; }
|
||||
if(e2 <= dx) { err += dx; y += sy; }
|
||||
}
|
||||
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lineColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
|
||||
Uint8 r, g, b, a;
|
||||
unpackColor(color, &r, &g, &b, &a);
|
||||
return lineRGBA(dst, x1, y1, x2, y2, r, g, b, a);
|
||||
}
|
||||
|
||||
int filledCircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
|
||||
Uint8 r, g, b, a;
|
||||
unpackColor(color, &r, &g, &b, &a);
|
||||
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
int dy;
|
||||
for(dy = -rad; dy <= rad; dy++) {
|
||||
int span = (int) floor(sqrt((double) rad * rad - (double) dy * dy));
|
||||
blendHLine(&t, x - span, x + span, y + dy, r, g, b, a);
|
||||
}
|
||||
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aacircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
|
||||
Uint8 r, g, b, a;
|
||||
unpackColor(color, &r, &g, &b, &a);
|
||||
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
int dx, dy;
|
||||
for(dy = -rad - 1; dy <= rad + 1; dy++)
|
||||
for(dx = -rad - 1; dx <= rad + 1; dx++) {
|
||||
double d = sqrt((double) dx * dx + (double) dy * dy);
|
||||
double coverage = 1.0 - fabs(d - rad);
|
||||
if(coverage > 0.0)
|
||||
blendPixel(&t, x + dx, y + dy, r, g, b, (int) (a * (coverage > 1.0 ? 1.0 : coverage)));
|
||||
}
|
||||
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filledPolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
if(n < 3) return -1;
|
||||
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
//A játék végig négyszögeket rajzol, azoknak bőven elég a veremben álló tömb;
|
||||
//képkockánként több tízezer malloc/free párt spórolunk vele.
|
||||
double inlineCrossings[16];
|
||||
double* crossings = inlineCrossings;
|
||||
if(n > (int)(sizeof(inlineCrossings) / sizeof(*inlineCrossings))) {
|
||||
crossings = (double*) malloc(n * sizeof(double));
|
||||
if(crossings == NULL) { endTarget(&t); return -1; }
|
||||
}
|
||||
|
||||
int minY = vy[0], maxY = vy[0];
|
||||
int i;
|
||||
for(i = 1; i < n; i++) {
|
||||
if(vy[i] < minY) minY = vy[i];
|
||||
if(vy[i] > maxY) maxY = vy[i];
|
||||
}
|
||||
|
||||
int yStart = minY < 0 ? 0 : minY;
|
||||
int yEnd = maxY > t.h - 1 ? t.h - 1 : maxY;
|
||||
|
||||
int y;
|
||||
for(y = yStart; y <= yEnd; y++) {
|
||||
int count = 0;
|
||||
for(i = 0; i < n; i++) {
|
||||
int j = (i + 1) % n;
|
||||
int y1 = vy[i], y2 = vy[j], x1 = vx[i], x2 = vx[j];
|
||||
if(y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; tmp = x1; x1 = x2; x2 = tmp; }
|
||||
|
||||
if((y >= y1 && y < y2) || (y == maxY && y > y1 && y <= y2))
|
||||
crossings[count++] = x1 + ((double) (y - y1) * (x2 - x1)) / (y2 - y1);
|
||||
}
|
||||
|
||||
if(count < 2) continue;
|
||||
|
||||
//Néhány elemre a beszúrásos rendezés gyorsabb, mint a qsort függvénypointeres hívogatása
|
||||
int k;
|
||||
for(i = 1; i < count; i++) {
|
||||
double key = crossings[i];
|
||||
for(k = i - 1; k >= 0 && crossings[k] > key; k--) crossings[k + 1] = crossings[k];
|
||||
crossings[k + 1] = key;
|
||||
}
|
||||
|
||||
for(i = 0; i + 1 < count; i += 2)
|
||||
blendHLine(&t, (int) floor(crossings[i] + 0.5), (int) floor(crossings[i + 1] + 0.5), y, r, g, b, a);
|
||||
}
|
||||
|
||||
if(crossings != inlineCrossings) free(crossings);
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aaLine(const target* t, double x0, double y0, double x1, double y1, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
bool steep = fabs(y1 - y0) > fabs(x1 - x0);
|
||||
double tmp;
|
||||
if(steep) { tmp = x0; x0 = y0; y0 = tmp; tmp = x1; x1 = y1; y1 = tmp; }
|
||||
if(x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; tmp = y0; y0 = y1; y1 = tmp; }
|
||||
|
||||
double dx = x1 - x0;
|
||||
double gradient = dx == 0.0 ? 0.0 : (y1 - y0) / dx;
|
||||
|
||||
int xStart = (int) floor(x0 + 0.5), xEnd = (int) floor(x1 + 0.5);
|
||||
double intersection = y0 + gradient * (xStart - x0);
|
||||
|
||||
int x;
|
||||
for(x = xStart; x <= xEnd; x++) {
|
||||
int base = (int) floor(intersection);
|
||||
double frac = intersection - base;
|
||||
|
||||
if(steep) {
|
||||
blendPixel(t, base, x, r, g, b, (int) (a * (1.0 - frac)));
|
||||
blendPixel(t, base + 1, x, r, g, b, (int) (a * frac));
|
||||
}
|
||||
else {
|
||||
blendPixel(t, x, base, r, g, b, (int) (a * (1.0 - frac)));
|
||||
blendPixel(t, x, base + 1, r, g, b, (int) (a * frac));
|
||||
}
|
||||
|
||||
intersection += gradient;
|
||||
}
|
||||
}
|
||||
|
||||
int aapolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
if(n < 2) return -1;
|
||||
|
||||
target t;
|
||||
if(!beginTarget(dst, &t)) return -1;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < n; i++) {
|
||||
int j = (i + 1) % n;
|
||||
aaLine(&t, vx[i], vy[i], vx[j], vy[j], r, g, b, a);
|
||||
}
|
||||
|
||||
endTarget(&t);
|
||||
return 0;
|
||||
}
|
||||
18
Forráskód/modules/auxiliary/gfxPrimitives.h
Normal file
18
Forráskód/modules/auxiliary/gfxPrimitives.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef GFXPRIMITIVES_H_INCLUDED
|
||||
#define GFXPRIMITIVES_H_INCLUDED
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void setRenderingEnabled(bool enabled);
|
||||
bool isRenderingEnabled();
|
||||
|
||||
int boxColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
|
||||
int boxRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
int lineColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
|
||||
int filledCircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);
|
||||
int aacircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);
|
||||
int filledPolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
int aapolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
|
||||
#endif // GFXPRIMITIVES_H_INCLUDED
|
||||
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
///Indításnál betölti a szükséges betűtípusokat.
|
||||
void openFonts() {
|
||||
SDL_EnableUNICODE(1);
|
||||
TTF_Init();
|
||||
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", 40);
|
||||
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", 48);
|
||||
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", 53);
|
||||
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", 120);
|
||||
if(!TTF_WasInit()) TTF_Init();
|
||||
|
||||
float scale = (float) screen -> h / designHeight;
|
||||
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(40 * scale)));
|
||||
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(48 * scale)));
|
||||
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", larger(1, (int)(53 * scale)));
|
||||
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(120 * scale)));
|
||||
}
|
||||
|
||||
///Ha már nem kellenek, felszabadítja a betűtípusokat.
|
||||
|
|
@ -20,10 +21,10 @@ void freeFonts() {
|
|||
}
|
||||
|
||||
///Itt tárolom a használható karaktereket. Eldönti, hogy a bemenet köztük van-e.
|
||||
bool isValidChar(Uint16 chr) {
|
||||
bool isValidChar(wchar_t chr) {
|
||||
if(('A' <= chr && chr <= 'Z') || ('a' <= chr && chr <= 'z') || ('0' <= chr && chr <= '9')) return true;
|
||||
|
||||
Uint16 validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
|
||||
wchar_t validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
|
||||
int i;
|
||||
for(i = 0; validChars[i] != 0; i++) if(chr == validChars[i])
|
||||
return true;
|
||||
|
|
@ -57,14 +58,14 @@ Sint16 percentageToPx(int percentage, bool isWidth) {
|
|||
* \param string vége
|
||||
* \return string konkatenált
|
||||
*/
|
||||
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
|
||||
wchar_t* concatUnicode(const wchar_t a[], const wchar_t b[]) {
|
||||
int aLength, bLength;
|
||||
for(aLength = 0; a[aLength] != 0; aLength++)
|
||||
;
|
||||
for(bLength = 0; b[bLength] != 0; bLength++)
|
||||
;
|
||||
|
||||
Uint16* newStr = (Uint16*) malloc((aLength + bLength - 1 + 100) * sizeof(Uint16));
|
||||
wchar_t* newStr = (wchar_t*) malloc((aLength + bLength - 1 + 100) * sizeof(wchar_t));
|
||||
int i = 0, ai, bi;
|
||||
for(ai = 0; ai < aLength; ai++)
|
||||
newStr[i++] = a[ai];
|
||||
|
|
@ -76,9 +77,79 @@ Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
|
|||
}
|
||||
|
||||
///A megjelenítendő szöveg közepét kell megadni x,y-ként. A szöveget Uint16*-ban, a betűtipust pedig a betűtipus enumból. Ugyan mindent x = 50-nel hívunk meg, ez később változhat, ezért hagyom meg paraméternek.
|
||||
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType) {
|
||||
void unicodePrintCentered(wchar_t textToWrite[], int x, int y, fontType fontType) {
|
||||
char utf8[2048];
|
||||
wideToUtf8(textToWrite, utf8, sizeof(utf8));
|
||||
utf8PrintCentered(utf8, x, y, fontType);
|
||||
}
|
||||
|
||||
///Ugyanaz, mint az unicodePrintCentered, csak utf-8-as bemenettel.
|
||||
void utf8PrintCentered(const char* textToWrite, int x, int y, fontType fontType) {
|
||||
if(!isRenderingEnabled()) return;
|
||||
|
||||
TTF_Font* currentFont = selectFont(fontType);
|
||||
SDL_FreeSurface(text);
|
||||
text = TTF_RenderUNICODE_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
|
||||
text = TTF_RenderUTF8_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
|
||||
if(text == NULL) return;
|
||||
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){percentageToPx(x, true) - text -> w / 2, percentageToPx(y, false) - text -> h / 2, 0, 0});
|
||||
}
|
||||
|
||||
int wideToUtf8(const wchar_t* source, char* destination, int destinationSize) {
|
||||
int written = 0;
|
||||
|
||||
for(; *source != 0; source++) {
|
||||
unsigned int c = (unsigned int) *source;
|
||||
int needed = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
|
||||
if(written + needed >= destinationSize) break;
|
||||
|
||||
switch(needed) {
|
||||
case 1:
|
||||
destination[written++] = c;
|
||||
break;
|
||||
case 2:
|
||||
destination[written++] = 0xC0 | (c >> 6);
|
||||
destination[written++] = 0x80 | (c & 0x3F);
|
||||
break;
|
||||
case 3:
|
||||
destination[written++] = 0xE0 | (c >> 12);
|
||||
destination[written++] = 0x80 | ((c >> 6) & 0x3F);
|
||||
destination[written++] = 0x80 | (c & 0x3F);
|
||||
break;
|
||||
default:
|
||||
destination[written++] = 0xF0 | (c >> 18);
|
||||
destination[written++] = 0x80 | ((c >> 12) & 0x3F);
|
||||
destination[written++] = 0x80 | ((c >> 6) & 0x3F);
|
||||
destination[written++] = 0x80 | (c & 0x3F);
|
||||
}
|
||||
}
|
||||
|
||||
destination[written] = 0;
|
||||
return written;
|
||||
}
|
||||
|
||||
int utf8ToWide(const char* source, wchar_t* destination, int destinationSize) {
|
||||
int written = 0;
|
||||
|
||||
while(*source != 0 && written < destinationSize - 1) {
|
||||
unsigned char lead = (unsigned char) *source++;
|
||||
unsigned int c;
|
||||
int continuations;
|
||||
|
||||
if(lead < 0x80) { c = lead; continuations = 0; }
|
||||
else if((lead & 0xE0) == 0xC0) { c = lead & 0x1F; continuations = 1; }
|
||||
else if((lead & 0xF0) == 0xE0) { c = lead & 0x0F; continuations = 2; }
|
||||
else if((lead & 0xF8) == 0xF0) { c = lead & 0x07; continuations = 3; }
|
||||
else continue;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < continuations; i++) {
|
||||
if((*source & 0xC0) != 0x80) break;
|
||||
c = (c << 6) | (*source++ & 0x3F);
|
||||
}
|
||||
|
||||
destination[written++] = (wchar_t) c;
|
||||
}
|
||||
|
||||
destination[written] = 0;
|
||||
return written;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@
|
|||
|
||||
void openFonts();
|
||||
void freeFonts();
|
||||
bool isValidChar(Uint16 chr);
|
||||
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]);
|
||||
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType);
|
||||
bool isValidChar(wchar_t chr);
|
||||
wchar_t* concatUnicode(const wchar_t a[], const wchar_t b[]);
|
||||
void unicodePrintCentered(wchar_t textToWrite[], int x, int y, fontType fontType);
|
||||
void utf8PrintCentered(const char* textToWrite, int x, int y, fontType fontType);
|
||||
int wideToUtf8(const wchar_t* source, char* destination, int destinationSize);
|
||||
int utf8ToWide(const char* source, wchar_t* destination, int destinationSize);
|
||||
|
||||
#endif // UNICODEPRINT_H_INCLUDED
|
||||
|
|
|
|||
Loading…
Reference in a new issue