Compare commits
1 Commits
main
...
wip/game-r
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bb961448d |
7
app.c
7
app.c
@ -28,10 +28,13 @@ void App_Init(App_t *app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Objects_Init(&app->graphics)) {
|
||||
if (!Objects_Init(&app->objects)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map_LoadSampleData();
|
||||
|
||||
app->isInGame = true;
|
||||
app->isRunning = true;
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ void App_Run(App_t *app) {
|
||||
}
|
||||
|
||||
void App_Shutdown(const App_t* app) {
|
||||
Objects_Destroy(&app->graphics);
|
||||
Objects_Destroy(&app->objects);
|
||||
Map_Destroy(&app->map);
|
||||
Bitmap_Destroy(&app->bitmap);
|
||||
Gui_Shutdown();
|
||||
|
||||
3
app.h
3
app.h
@ -12,11 +12,12 @@
|
||||
|
||||
typedef struct App {
|
||||
bool isRunning;
|
||||
bool isInGame;
|
||||
SystemMetrics_t metrics;
|
||||
ConfigParams_t configParams;
|
||||
Map_t map;
|
||||
Bitmap_t bitmap;
|
||||
Objects_t graphics;
|
||||
Objects_t objects;
|
||||
Gui_t gui;
|
||||
} App_t;
|
||||
|
||||
|
||||
14
gui.c
14
gui.c
@ -39,8 +39,8 @@ void Gui_StartRender() {
|
||||
ImGui_NewFrame();
|
||||
}
|
||||
|
||||
void Gui_Render(Gui_t *gui, ConfigParams_t *configParams) {
|
||||
Gui_RenderMainMenu(gui);
|
||||
void Gui_Render(Gui_t *gui, ConfigParams_t *configParams, const bool inGame) {
|
||||
Gui_RenderMainMenu(gui, inGame);
|
||||
Gui_RenderPreferences_Dialog(gui, configParams);
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ void Gui_Shutdown() {
|
||||
ImGui_DestroyContext(NULL);
|
||||
}
|
||||
|
||||
void Gui_RenderMainMenu(Gui_t *gui) {
|
||||
void Gui_RenderMainMenu(Gui_t *gui, const bool inGame) {
|
||||
if (!ImGui_BeginMainMenuBar()) {
|
||||
return;
|
||||
}
|
||||
@ -82,20 +82,20 @@ void Gui_RenderMainMenu(Gui_t *gui) {
|
||||
if (ImGui_MenuItem("Journey Onward")) {
|
||||
}
|
||||
|
||||
if (ImGui_MenuItem("End Game")) {
|
||||
if (ImGui_MenuItemEx("End Game", NULL, NULL, inGame)) {
|
||||
}
|
||||
|
||||
ImGui_EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui_BeginMenu("Info")) {
|
||||
if (ImGui_MenuItem("Change Data")) {
|
||||
if (ImGui_MenuItemEx("Change Data", NULL, NULL, inGame)) {
|
||||
}
|
||||
|
||||
if (ImGui_MenuItem("Userlist")) {
|
||||
if (ImGui_MenuItemEx("Userlist", NULL, NULL, inGame)) {
|
||||
}
|
||||
|
||||
if (ImGui_MenuItem("Comments")) {
|
||||
if (ImGui_MenuItemEx("Comments", NULL, NULL, inGame)) {
|
||||
}
|
||||
|
||||
ImGui_EndMenu();
|
||||
|
||||
4
gui.h
4
gui.h
@ -16,11 +16,11 @@ typedef struct Gui {
|
||||
void Gui_Init(Gui_t* gui);
|
||||
void Gui_ProcessEvent(const SDL_Event* event);
|
||||
void Gui_StartRender();
|
||||
void Gui_Render(Gui_t* gui, ConfigParams_t* configParams);
|
||||
void Gui_Render(Gui_t* gui, ConfigParams_t* configParams, bool inGame);
|
||||
void Gui_FinishRender();
|
||||
void Gui_Shutdown();
|
||||
|
||||
void Gui_RenderMainMenu(Gui_t* gui);
|
||||
void Gui_RenderMainMenu(Gui_t* gui, bool inGame);
|
||||
void Gui_RenderPreferences_Dialog(Gui_t* gui, ConfigParams_t* configParams);
|
||||
|
||||
#endif //TIBIA_GUI_H
|
||||
78
objects.c
78
objects.c
@ -6,9 +6,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <SDL3/SDL_iostream.h>
|
||||
#include <SDL3/SDL_log.h>
|
||||
#include <SDL3/SDL_messagebox.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "window.h"
|
||||
|
||||
bool Objects_Init(Objects_t *objects) {
|
||||
memset(objects->spriteTable, 0, sizeof(objects->spriteTable));
|
||||
@ -22,6 +21,7 @@ bool Objects_Init(Objects_t *objects) {
|
||||
}
|
||||
|
||||
memset(objects->activeObjectList, 0, sizeof(objects->activeObjectList));
|
||||
memset(objects->activeTextures, 0, sizeof(objects->activeTextures));
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_CUSTOM, "Objects_Init: memory allocated");
|
||||
|
||||
@ -115,6 +115,7 @@ bool Objects_LoadData(Objects_t *objects) {
|
||||
|
||||
bool Objects_LoadSprites(Objects_t *objects) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_CUSTOM, "Objects_LoadSprites: loading object sprites.");
|
||||
SDL_Renderer* renderer = Window_GetRenderer();
|
||||
|
||||
// Free existing sprites to prevent memory leaks
|
||||
for (int i = 0; i < SPRITE_TABLE_SIZE; i++) {
|
||||
@ -186,6 +187,9 @@ bool Objects_LoadSprites(Objects_t *objects) {
|
||||
}
|
||||
}
|
||||
|
||||
objects->spriteTable[spriteID] = spriteBuffer;
|
||||
objects->activeTextures[spriteID] = Objects_TextureFromRaw(renderer, spriteBuffer);
|
||||
|
||||
spritesLoaded++;
|
||||
}
|
||||
|
||||
@ -199,4 +203,72 @@ void Objects_Destroy(const Objects_t *objects) {
|
||||
for (int i = 0; i < THING_DATA_POOL_SIZE; i++) {
|
||||
free(objects->thingDataPool[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ACTIVE_OBJECT_LIST_SIZE; i++) {
|
||||
if (objects->activeTextures[i]) {
|
||||
SDL_DestroyTexture(objects->activeTextures[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Texture* Objects_GetSpriteTexture(const Objects_t *objects, const uint16_t spriteID) {
|
||||
if (spriteID >= SPRITE_TABLE_SIZE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return objects->activeTextures[spriteID];
|
||||
}
|
||||
|
||||
SDL_Texture* Objects_TextureFromRaw(SDL_Renderer* renderer, uint8_t* rawData) {
|
||||
if (!rawData) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint16_t totalSize = *(uint16_t*) rawData;
|
||||
uint8_t* data = rawData + 2;
|
||||
int readOffset = 0;
|
||||
|
||||
SDL_Surface* surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||
if (!surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_LockSurface(surface);
|
||||
uint32_t* pixels = surface->pixels;
|
||||
|
||||
memset(pixels, 0, 32 * 32 * 4);
|
||||
|
||||
int currentPixel = 0;
|
||||
while (readOffset < totalSize - 2 && currentPixel < 1024) {
|
||||
const uint16_t transparentRaw = *(uint16_t*)(data + readOffset);
|
||||
readOffset += 2;
|
||||
|
||||
const uint16_t transparentBytes = transparentRaw % 0x5A0;
|
||||
const int skipPixels = transparentBytes / 3;
|
||||
|
||||
currentPixel += skipPixels;
|
||||
|
||||
const uint16_t colorBytes = *(uint16_t*)(data + readOffset);
|
||||
readOffset += 2;
|
||||
|
||||
const int drawPixels = colorBytes / 3;
|
||||
for (int i = 0; i < drawPixels; i++) {
|
||||
if (currentPixel >= 1024) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t r = data[readOffset++];
|
||||
const uint8_t g = data[readOffset++];
|
||||
const uint8_t b = data[readOffset++];
|
||||
|
||||
pixels[currentPixel++] = SDL_MapRGBA(SDL_GetPixelFormatDetails(surface->format), NULL, r, g, b, 255);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(surface);
|
||||
|
||||
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_DestroySurface(surface);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <SDL3/SDL_render.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
@ -25,11 +26,16 @@ typedef struct Objects {
|
||||
void* spriteTable[SPRITE_TABLE_SIZE];
|
||||
void* thingDataPool[THING_DATA_POOL_SIZE];
|
||||
void* activeObjectList[ACTIVE_OBJECT_LIST_SIZE];
|
||||
SDL_Texture* activeTextures[SPRITE_TABLE_SIZE];
|
||||
} Objects_t;
|
||||
|
||||
bool Objects_Init(Objects_t* objects);
|
||||
bool Objects_LoadData(Objects_t* objects);
|
||||
bool Objects_LoadSprites(Objects_t* objects);
|
||||
void Objects_Destroy(const Objects_t* objects);
|
||||
SDL_Texture* Objects_GetSpriteTexture(const Objects_t* objects, uint16_t spriteID);
|
||||
|
||||
// TODO: move this somewhere else
|
||||
SDL_Texture* Objects_TextureFromRaw(SDL_Renderer* renderer, uint8_t* rawData);
|
||||
|
||||
#endif //TIBIA_OBJECTS_H
|
||||
104
render.c
104
render.c
@ -6,6 +6,48 @@
|
||||
#include "window.h"
|
||||
#include "gui.h"
|
||||
|
||||
#define MAP_WIDTH_TILES 15
|
||||
#define MAP_HEIGHT_TILES 11
|
||||
#define TILE_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
uint16_t groundSpriteID;
|
||||
} MapTile;
|
||||
|
||||
MapTile g_ClientMapData[MAP_WIDTH_TILES][MAP_HEIGHT_TILES];
|
||||
|
||||
void Map_LoadSampleData() {
|
||||
SDL_Log("Map_LoadSampleData: Populating dummy map...");
|
||||
|
||||
// These IDs are guesses for Tibia 1.03 based on standard asset order.
|
||||
// If these show up as items (like swords/apples), try swapping them.
|
||||
// Usually: 0-100 contains basic ground tiles.
|
||||
uint16_t ID_GRASS = 45;
|
||||
uint16_t ID_DIRT = 40;
|
||||
uint16_t ID_STONE = 50;
|
||||
|
||||
for (int x = 0; x < MAP_WIDTH_TILES; x++) {
|
||||
for (int y = 0; y < MAP_HEIGHT_TILES; y++) {
|
||||
|
||||
// 1. Default to Grass
|
||||
uint16_t tileID = ID_GRASS;
|
||||
|
||||
// 2. Create a Checkerboard pattern
|
||||
if ((x + y) % 2 == 0) {
|
||||
tileID = ID_DIRT;
|
||||
}
|
||||
|
||||
// 3. Create a Stone path in the middle row
|
||||
if (y == 5) {
|
||||
tileID = ID_STONE;
|
||||
}
|
||||
|
||||
// 4. Assign to the map
|
||||
g_ClientMapData[x][y].groundSpriteID = x * MAP_HEIGHT_TILES + y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Render_Frame(App_t* app) {
|
||||
Gui_StartRender();
|
||||
|
||||
@ -14,7 +56,9 @@ void Render_Frame(App_t* app) {
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
Render_MainWindowBackground(app);
|
||||
Gui_Render(&app->gui, &app->configParams);
|
||||
Render_GameView(app);
|
||||
|
||||
Gui_Render(&app->gui, &app->configParams, app->isInGame);
|
||||
|
||||
Gui_FinishRender();
|
||||
SDL_RenderPresent(renderer);
|
||||
@ -29,7 +73,7 @@ void Render_MainWindowBackground(const App_t *app) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int TILE_SIZE = 128;
|
||||
// const int TILE_SIZE = 128;
|
||||
|
||||
// Calculate how many tiles we need to cover the screen
|
||||
const int tilesX = app->metrics.screenWidth / TILE_SIZE + 1;
|
||||
@ -48,3 +92,59 @@ void Render_MainWindowBackground(const App_t *app) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Render_GameView(const App_t *app) {
|
||||
if (!app->isInGame) {
|
||||
Render_TitleScreen(app);
|
||||
return;
|
||||
}
|
||||
|
||||
Render_Game(app);
|
||||
}
|
||||
|
||||
void Render_TitleScreen(const App_t *app) {
|
||||
// TODO: properly calculate the window sizes and spacings
|
||||
SDL_Renderer *renderer = Window_GetRenderer();
|
||||
int winW, winH;
|
||||
SDL_GetRenderOutputSize(renderer, &winW, &winH);
|
||||
|
||||
const SDL_FRect destRect = {
|
||||
0.0f, 30.0f,
|
||||
(float)winW, (float)winH - 150.0f
|
||||
};
|
||||
|
||||
SDL_RenderTexture(renderer, app->bitmap.tibiaTexture, NULL, &destRect);
|
||||
}
|
||||
|
||||
void Render_Game(const App_t *app) {
|
||||
SDL_Renderer *renderer = Window_GetRenderer();
|
||||
|
||||
for (int x = 0; x < MAP_WIDTH_TILES; x++) {
|
||||
for (int y = 0; y < MAP_HEIGHT_TILES; y++) {
|
||||
const MapTile* tile = &g_ClientMapData[x][y];
|
||||
|
||||
if (tile->groundSpriteID == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int screenX = x * TILE_SIZE;
|
||||
const int screenY = y * TILE_SIZE;
|
||||
|
||||
SDL_Texture* texture = Objects_GetSpriteTexture(&app->objects, tile->groundSpriteID);
|
||||
if (texture) {
|
||||
SDL_FRect destRect = {
|
||||
(float)screenX,
|
||||
(float)screenY,
|
||||
(float)TILE_SIZE,
|
||||
(float)TILE_SIZE
|
||||
};
|
||||
|
||||
SDL_RenderTexture(renderer, texture, NULL, &destRect);
|
||||
} else {
|
||||
SDL_FRect destRect = { (float)screenX, (float)screenY, 32.0f, 32.0f };
|
||||
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); // Green for ground
|
||||
SDL_RenderFillRect(renderer, &destRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
render.h
6
render.h
@ -8,8 +8,14 @@
|
||||
|
||||
#include "app.h"
|
||||
|
||||
void Map_LoadSampleData();
|
||||
|
||||
void Render_Frame(App_t* app);
|
||||
void Render_MainWindowBackground(const App_t* app);
|
||||
void Render_GameView(const App_t* app);
|
||||
|
||||
void Render_TitleScreen(const App_t* app);
|
||||
void Render_Game(const App_t* app);
|
||||
|
||||
void Render_DrawWindowFrame(SDL_Renderer* renderer, int x, int y, int w, int h);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user