From fab76290bce7370f6b57956328be1ca548d3e654 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 18:07:46 -0400 Subject: [PATCH 01/19] modify makefile to detect windows or linux --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59df3ee..c3711cb 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ TEST_OBJS := $(foreach file,$(TEST_SRCS),$(BUILD_DIR)/$(file:.c=.o)) ifeq ($(OS),Windows_NT) LIB_FILE := $(DIST_DIR)/sm64.dll + TEST_FILE := $(DIST_DIR)/run-test.exe endif DUMMY != mkdir -p $(ALL_DIRS) build/test src/decomp/mario $(DIST_DIR)/include @@ -61,8 +62,11 @@ $(BUILD_DIR)/test/%.o: test/%.c $(CC) -c $(CFLAGS) -o $@ $< $(TEST_FILE): $(LIB_FILE) $(TEST_OBJS) +ifeq ($(OS),Windows_NT) + $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lglew32 -lopengl32 -lSDL2 -lSDL2main -lm +else $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm - +endif lib: $(LIB_FILE) $(LIB_H_FILE) From 2f361951b51925da3a8d3de24412dd6d69dbc14f Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 18:08:26 -0400 Subject: [PATCH 02/19] use real gAudioRandom for random jump sound, etc. --- src/decomp/game/mario.c | 2 +- src/decomp/game/mario_actions_airborne.c | 2 +- src/decomp/game/mario_actions_cutscene.c | 2 +- src/decomp/game/mario_actions_stationary.c | 2 +- src/decomp/shim.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/decomp/game/mario.c b/src/decomp/game/mario.c index 44f9531..1a594ce 100644 --- a/src/decomp/game/mario.c +++ b/src/decomp/game/mario.c @@ -7,7 +7,7 @@ #include "../include/sm64.h" #include "area.h" -// #include "audio/external.h" +#include "../audio/external.h" // #include "behavior_actions.h" // #include "behavior_data.h" #include "camera.h" diff --git a/src/decomp/game/mario_actions_airborne.c b/src/decomp/game/mario_actions_airborne.c index 1689168..54450ba 100644 --- a/src/decomp/game/mario_actions_airborne.c +++ b/src/decomp/game/mario_actions_airborne.c @@ -5,7 +5,7 @@ #include "../include/sm64.h" #include "area.h" -//#include "audio/external.h" +#include "../audio/external.h" #include "camera.h" #include "../engine/graph_node.h" #include "../engine/math_util.h" diff --git a/src/decomp/game/mario_actions_cutscene.c b/src/decomp/game/mario_actions_cutscene.c index 94e639c..1eecf0b 100644 --- a/src/decomp/game/mario_actions_cutscene.c +++ b/src/decomp/game/mario_actions_cutscene.c @@ -7,7 +7,7 @@ //#include "prevent_bss_reordering.h" #include "../include/sm64.h" #include "area.h" -//#include "audio/external.h" +#include "../audio/external.h" //#include "behavior_data.h" #include "camera.h" //#include "dialog_ids.h" diff --git a/src/decomp/game/mario_actions_stationary.c b/src/decomp/game/mario_actions_stationary.c index 704cddf..0f042dd 100644 --- a/src/decomp/game/mario_actions_stationary.c +++ b/src/decomp/game/mario_actions_stationary.c @@ -5,7 +5,7 @@ #include "../include/sm64.h" #include "area.h" -//#include "audio/external.h" +#include "../audio/external.h" //#include "behavior_data.h" #include "camera.h" #include "../engine/math_util.h" diff --git a/src/decomp/shim.h b/src/decomp/shim.h index 11c762e..27d1672 100644 --- a/src/decomp/shim.h +++ b/src/decomp/shim.h @@ -20,7 +20,7 @@ #define gSpecialTripleJump (g_state->mgSpecialTripleJump) #define gCurrLevelNum (g_state->mgCurrLevelNum) #define gCameraMovementFlags (g_state->mgCameraMovementFlags) -#define gAudioRandom (g_state->mgAudioRandom) +//#define gAudioRandom (g_state->mgAudioRandom) #define gShowDebugText (g_state->mgShowDebugText) #define gDebugLevelSelect (g_state->mgDebugLevelSelect) #define gCurrSaveFileNum (g_state->mgCurrSaveFileNum) From 4a40f669819d8fc41a1643a159a565bed54bc37f Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 18:09:30 -0400 Subject: [PATCH 03/19] set cameraToObject to 0 it'll make both of your ears enjoy sounds rather than your right one only --- src/libsm64.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsm64.c b/src/libsm64.c index c3df3e7..acbf28f 100644 --- a/src/libsm64.c +++ b/src/libsm64.c @@ -228,6 +228,10 @@ SM64_LIB_FN void sm64_mario_tick( int32_t marioId, const struct SM64MarioInputs update_button( inputs->buttonB, B_BUTTON ); update_button( inputs->buttonZ, Z_TRIG ); + gMarioState->marioObj->header.gfx.cameraToObject[0] = 0; + gMarioState->marioObj->header.gfx.cameraToObject[1] = 0; + gMarioState->marioObj->header.gfx.cameraToObject[2] = 0; + gMarioState->area->camera->yaw = atan2s( inputs->camLookZ, inputs->camLookX ); gController.stickX = -64.0f * inputs->stickX; From 6433511a6586a9d8477a5c5ef417731b8feaaf95 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:29:50 -0400 Subject: [PATCH 04/19] add test/audio.c and test/audio.h --- test/audio.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/audio.h | 6 +++++ 2 files changed, 75 insertions(+) create mode 100644 test/audio.c create mode 100644 test/audio.h diff --git a/test/audio.c b/test/audio.c new file mode 100644 index 0000000..071d77f --- /dev/null +++ b/test/audio.c @@ -0,0 +1,69 @@ +#include "audio.h" + +#include +#include +#include +#include + +#include "context.h" + +static SDL_AudioDeviceID dev; + +pthread_t gSoundThread; +long long timeInMilliseconds(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + return(((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000); +} + +void* audio_thread(void* keepAlive) +{ + // from https://github.com/ckosmic/libsm64/blob/audio/src/libsm64.c#L535-L555 + // except keepAlive is a null pointer here, so don't use it + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); + + long long currentTime = timeInMilliseconds(); + long long targetTime = 0; + while(1) + { + //if(!*((bool*)keepAlive)) return NULL; + + int16_t audioBuffer[544 * 2 * 2]; + uint32_t numSamples = sm64_audio_tick(SDL_GetQueuedAudioSize(dev)/4, 1100, audioBuffer); + if (SDL_GetQueuedAudioSize(dev)/4 < 6000) + SDL_QueueAudio(dev, audioBuffer, numSamples * 2 * 4); + + targetTime = currentTime + 33; + while (timeInMilliseconds() < targetTime) + { + usleep(100); + //if(!*((bool*)keepAlive)) return NULL; + } + currentTime = timeInMilliseconds(); + } +} + +void audio_init() +{ + SDL_AudioSpec want, have; + SDL_zero(want); + want.freq = 32000; + want.format = AUDIO_S16; + want.channels = 2; + want.samples = 512; + want.callback = NULL; + dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); + if (dev == 0) { + fprintf(stderr, "SDL_OpenAudio error: %s\n", SDL_GetError()); + return; + } + SDL_PauseAudioDevice(dev, 0); + + // it's best to run audio in a separate thread + pthread_create(&gSoundThread, NULL, audio_thread, NULL); +} + diff --git a/test/audio.h b/test/audio.h new file mode 100644 index 0000000..9f2d934 --- /dev/null +++ b/test/audio.h @@ -0,0 +1,6 @@ +#ifndef AUDIO_H +#define AUDIO_H + +void audio_init(); + +#endif \ No newline at end of file From 815d5382f2ab7035db461fff080ea8659ecfb4ab Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:30:12 -0400 Subject: [PATCH 05/19] add OpenGL 2.0 and 3.3 Core renderers --- test/gl20/gl20_renderer.c | 171 ++++++++++++++++ test/gl20/gl20_renderer.h | 6 + test/gl33core/gl33core_renderer.c | 313 ++++++++++++++++++++++++++++++ test/gl33core/gl33core_renderer.h | 6 + test/renderer.h | 57 ++++++ 5 files changed, 553 insertions(+) create mode 100644 test/gl20/gl20_renderer.c create mode 100644 test/gl20/gl20_renderer.h create mode 100644 test/gl33core/gl33core_renderer.c create mode 100644 test/gl33core/gl33core_renderer.h create mode 100644 test/renderer.h diff --git a/test/gl20/gl20_renderer.c b/test/gl20/gl20_renderer.c new file mode 100644 index 0000000..cf846aa --- /dev/null +++ b/test/gl20/gl20_renderer.c @@ -0,0 +1,171 @@ +#include "gl20_renderer.h" + +#include + +#include "../../src/libsm64.h" +#include "../renderer.h" +#include "../context.h" +#include "../level.h" +#include + +static void load_collision_mesh( CollisionMesh *mesh ) +{ + mesh->num_vertices = 3 * surfaces_count; + mesh->position = malloc( sizeof( float ) * surfaces_count * 9 ); + mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 ); + mesh->color = malloc( sizeof( float ) * surfaces_count * 9 ); + mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 ); + + for( size_t i = 0; i < surfaces_count; ++i ) + { + const struct SM64Surface *surf = &surfaces[i]; + + float x1 = mesh->position[9*i+0] = surf->vertices[0][0]; + float y1 = mesh->position[9*i+1] = surf->vertices[0][1]; + float z1 = mesh->position[9*i+2] = surf->vertices[0][2]; + float x2 = mesh->position[9*i+3] = surf->vertices[1][0]; + float y2 = mesh->position[9*i+4] = surf->vertices[1][1]; + float z2 = mesh->position[9*i+5] = surf->vertices[1][2]; + float x3 = mesh->position[9*i+6] = surf->vertices[2][0]; + float y3 = mesh->position[9*i+7] = surf->vertices[2][1]; + float z3 = mesh->position[9*i+8] = surf->vertices[2][2]; + + float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2); + float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2); + float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2); + float mag = sqrtf(nx * nx + ny * ny + nz * nz); + nx /= mag; + ny /= mag; + nz /= mag; + + mesh->normal[9*i+0] = nx; + mesh->normal[9*i+1] = ny; + mesh->normal[9*i+2] = nz; + mesh->normal[9*i+3] = nx; + mesh->normal[9*i+4] = ny; + mesh->normal[9*i+5] = nz; + mesh->normal[9*i+6] = nx; + mesh->normal[9*i+7] = ny; + mesh->normal[9*i+8] = nz; + + for (int j=0; j<9; j++) + mesh->color[9*i+j] = (0.5 + 0.25 * 1) * (.5+.5*mesh->normal[9*i+j]); + + mesh->index[3*i+0] = 3*i+0; + mesh->index[3*i+1] = 3*i+1; + mesh->index[3*i+2] = 3*i+2; + } +} + +static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) +{ + mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) ); + for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i ) + mesh->index[i] = i; + + mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES; +} + +static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) +{ + if( mesh->index == NULL ) + load_mario_mesh( mesh, marioGeo ); + + mesh->num_vertices = 3 * marioGeo->numTrianglesUsed; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(3, GL_FLOAT, 0, marioGeo->position); + glNormalPointer(GL_FLOAT, 0, marioGeo->normal); + glColorPointer(3, GL_FLOAT, 0, marioGeo->color); + glTexCoordPointer(2, GL_FLOAT, 0, marioGeo->uv); +} + +static void gl20_init(RenderState *renderState, uint8_t *marioTexture) +{ + load_collision_mesh( &renderState->collision ); + + glEnable( GL_CULL_FACE ); + glCullFace( GL_BACK ); + glClearColor( 0.2f, 0.2f, 0.2f, 1.0f ); + glDepthMask( GL_TRUE ); + glDepthFunc( GL_LEQUAL ); + glEnable( GL_DEPTH_TEST ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_BLEND ); + glColor4f(1,1,1,1); + + glGenTextures( 1, &renderState->mario_texture ); + glBindTexture( GL_TEXTURE_2D, renderState->mario_texture ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture); +} + +static void gl20_draw(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo) +{ + mat4 model, view, projection; + glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection ); + glm_translate( view, (float*)camPos ); + glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view ); + glm_mat4_identity( model ); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((GLfloat*)projection); + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((GLfloat*)view); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + // draw world + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, renderState->collision.position); + glNormalPointer(GL_FLOAT, 0, renderState->collision.normal); + glColorPointer(3, GL_FLOAT, 0, renderState->collision.color); + glDrawElements(GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index); + + // create lighting on the scene + GLfloat light_position[] = { camPos[0], camPos[1], camPos[2], 1 }; + GLfloat light_diffuse[] = { 0.6f, 0.6f, 0.6f, 1 }; + GLfloat light_model[] = { 0.5f, 0.5f, 0.5f, 1 }; + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_model); + glShadeModel(GL_SMOOTH); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + // first, draw geometry without Mario's texture. + update_mario_mesh( &renderState->mario, marioGeo ); + uint32_t triangleSize = renderState->mario.num_vertices; + + glDrawElements(GL_TRIANGLES, triangleSize, GL_UNSIGNED_SHORT, renderState->mario.index); + + // now disable the color array and enable the texture. + glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, renderState->mario_texture); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glDrawElements(GL_TRIANGLES, triangleSize, GL_UNSIGNED_SHORT, renderState->mario.index); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); +} + +struct Renderer gl20_renderer = { + gl20_init, + gl20_draw +}; diff --git a/test/gl20/gl20_renderer.h b/test/gl20/gl20_renderer.h new file mode 100644 index 0000000..6b5afd2 --- /dev/null +++ b/test/gl20/gl20_renderer.h @@ -0,0 +1,6 @@ +#ifndef GL20_RENDERER_H +#define GL20_RENDERER_H + +extern struct Renderer gl20_renderer; + +#endif diff --git a/test/gl33core/gl33core_renderer.c b/test/gl33core/gl33core_renderer.c new file mode 100644 index 0000000..fb6d24f --- /dev/null +++ b/test/gl33core/gl33core_renderer.c @@ -0,0 +1,313 @@ +#include "gl33core_renderer.h" + +#include + +#include "../../src/libsm64.h" +#include "../renderer.h" +#include "../context.h" +#include "../cglm.h" +#include "../level.h" + +static const char *MARIO_SHADER = +"\n uniform mat4 view;" +"\n uniform mat4 projection;" +"\n uniform sampler2D marioTex;" +"\n " +"\n v2f vec3 v_color;" +"\n v2f vec3 v_normal;" +"\n v2f vec3 v_light;" +"\n v2f vec2 v_uv;" +"\n " +"\n #ifdef VERTEX" +"\n " +"\n layout(location = 0) in vec3 position;" +"\n layout(location = 1) in vec3 normal;" +"\n layout(location = 2) in vec3 color;" +"\n layout(location = 3) in vec2 uv;" +"\n " +"\n void main()" +"\n {" +"\n v_color = color;" +"\n v_normal = normal;" +"\n v_light = transpose( mat3( view )) * normalize( vec3( 1 ));" +"\n v_uv = uv;" +"\n " +"\n gl_Position = projection * view * vec4( position, 1. );" +"\n }" +"\n " +"\n #endif" +"\n #ifdef FRAGMENT" +"\n " +"\n out vec4 color;" +"\n " +"\n void main() " +"\n {" +"\n float light = .5 + .5 * clamp( dot( v_normal, v_light ), 0., 1. );" +"\n vec4 texColor = texture2D( marioTex, v_uv );" +"\n vec3 mainColor = mix( v_color, texColor.rgb, texColor.a ); // v_uv.x >= 0. ? texColor.a : 0. );" +"\n color = vec4( mainColor * light, 1 );" +"\n }" +"\n " +"\n #endif" +; +static const char *WORLD_SHADER = +"\n uniform mat4 model;" +"\n uniform mat4 view;" +"\n uniform mat4 projection;" +"\n uniform sampler2D tex;" +"\n " +"\n v2f vec3 v_normal;" +"\n v2f vec3 v_worldPos;" +"\n " +"\n #ifdef VERTEX" +"\n " +"\n layout(location = 0) in vec3 position;" +"\n layout(location = 1) in vec3 normal;" +"\n " +"\n void main()" +"\n {" +"\n v_normal = inverse(mat3(model)) * normal;" +"\n vec4 worldPos4 = model * vec4(position, 1.);" +"\n v_worldPos = worldPos4.xyz;" +"\n gl_Position = projection * view * worldPos4;" +"\n }" +"\n " +"\n #endif" +"\n #ifdef FRAGMENT" +"\n " +"\n vec3 tri( vec3 x )" +"\n {" +"\n return abs(x-floor(x)-.5);" +"\n } " +"\n float surfFunc( vec3 p )" +"\n {" +"\n float n = dot(tri(p*.15 + tri(p.yzx*.075)), vec3(.444));" +"\n p = p*1.5773 - n;" +"\n p.yz = vec2(p.y + p.z, p.z - p.y) * .866;" +"\n p.xz = vec2(p.x + p.z, p.z - p.x) * .866;" +"\n n += dot(tri(p*.225 + tri(p.yzx*.1125)), vec3(.222)); " +"\n return abs(n-.5)*1.9 + (1.-abs(sin(n*9.)))*.05;" +"\n }" +"\n " +"\n const vec3 light_x = vec3(-1.0, 0.4, 0.9);" +"\n " +"\n out vec4 color;" +"\n " +"\n void main() " +"\n {" +"\n float surfy = surfFunc( v_worldPos / 50. );" +"\n float brightness = smoothstep( .2, .3, surfy );" +"\n " +"\n color = vec4( (0.5 + 0.25 * brightness) * (.5+.5*v_normal), 1 );" +"\n }" +"\n " +"\n #endif" +; + +static void load_collision_mesh( CollisionMesh *mesh ) +{ + mesh->num_vertices = 3 * surfaces_count; + mesh->position = malloc( sizeof( float ) * surfaces_count * 9 ); + mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 ); + mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 ); + + for( size_t i = 0; i < surfaces_count; ++i ) + { + const struct SM64Surface *surf = &surfaces[i]; + + float x1 = mesh->position[9*i+0] = surf->vertices[0][0]; + float y1 = mesh->position[9*i+1] = surf->vertices[0][1]; + float z1 = mesh->position[9*i+2] = surf->vertices[0][2]; + float x2 = mesh->position[9*i+3] = surf->vertices[1][0]; + float y2 = mesh->position[9*i+4] = surf->vertices[1][1]; + float z2 = mesh->position[9*i+5] = surf->vertices[1][2]; + float x3 = mesh->position[9*i+6] = surf->vertices[2][0]; + float y3 = mesh->position[9*i+7] = surf->vertices[2][1]; + float z3 = mesh->position[9*i+8] = surf->vertices[2][2]; + + float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2); + float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2); + float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2); + float mag = sqrtf(nx * nx + ny * ny + nz * nz); + nx /= mag; + ny /= mag; + nz /= mag; + + mesh->normal[9*i+0] = nx; + mesh->normal[9*i+1] = ny; + mesh->normal[9*i+2] = nz; + mesh->normal[9*i+3] = nx; + mesh->normal[9*i+4] = ny; + mesh->normal[9*i+5] = nz; + mesh->normal[9*i+6] = nx; + mesh->normal[9*i+7] = ny; + mesh->normal[9*i+8] = nz; + + mesh->index[3*i+0] = 3*i+0; + mesh->index[3*i+1] = 3*i+1; + mesh->index[3*i+2] = 3*i+2; + } + + glGenVertexArrays( 1, &mesh->vao ); + glBindVertexArray( mesh->vao ); + + #define X( loc, buff, arr, type ) do { \ + glGenBuffers( 1, &buff ); \ + glBindBuffer( GL_ARRAY_BUFFER, buff ); \ + glBufferData( GL_ARRAY_BUFFER, mesh->num_vertices*sizeof( type ), arr, GL_STATIC_DRAW ); \ + glEnableVertexAttribArray( loc ); \ + glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \ + } while( 0 ) + + X( 0, mesh->position_buffer, mesh->position, vec3 ); + X( 1, mesh->normal_buffer, mesh->normal, vec3 ); + + #undef X +} + +static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) +{ + mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) ); + for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i ) + mesh->index[i] = i; + + mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES; + + glGenVertexArrays( 1, &mesh->vao ); + glBindVertexArray( mesh->vao ); + + #define X( loc, buff, arr, type ) do { \ + glGenBuffers( 1, &buff ); \ + glBindBuffer( GL_ARRAY_BUFFER, buff ); \ + glBufferData( GL_ARRAY_BUFFER, sizeof( type ) * 3 * SM64_GEO_MAX_TRIANGLES, arr, GL_DYNAMIC_DRAW ); \ + glEnableVertexAttribArray( loc ); \ + glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \ + } while( 0 ) + + X( 0, mesh->position_buffer, marioGeo->position, vec3 ); + X( 1, mesh->normal_buffer, marioGeo->normal, vec3 ); + X( 2, mesh->color_buffer, marioGeo->color, vec3 ); + X( 3, mesh->uv_buffer, marioGeo->uv, vec2 ); + + #undef X +} + +static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) +{ + if( mesh->index == NULL ) + load_mario_mesh( mesh, marioGeo ); + + mesh->num_vertices = 3 * marioGeo->numTrianglesUsed; + + glBindBuffer( GL_ARRAY_BUFFER, mesh->position_buffer ); + glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->position, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, mesh->normal_buffer ); + glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->normal, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, mesh->color_buffer ); + glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->color, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, mesh->uv_buffer ); + glBufferData( GL_ARRAY_BUFFER, sizeof( vec2 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->uv, GL_DYNAMIC_DRAW ); +} + +static GLuint shader_compile( const char *shaderContents, size_t shaderContentsLength, GLenum shaderType ) +{ + const GLchar *shaderDefine = shaderType == GL_VERTEX_SHADER + ? "\n#version 330\n#define VERTEX \n#define v2f out\n" + : "\n#version 330\n#define FRAGMENT\n#define v2f in \n"; + + const GLchar *shaderStrings[2] = { shaderDefine, shaderContents }; + GLint shaderStringLengths[2] = { strlen( shaderDefine ), (GLint)shaderContentsLength }; + + GLuint shader = glCreateShader( shaderType ); + glShaderSource( shader, 2, shaderStrings, shaderStringLengths ); + glCompileShader( shader ); + + GLint isCompiled; + glGetShaderiv( shader, GL_COMPILE_STATUS, &isCompiled ); + if( isCompiled == GL_FALSE ) + { + GLint maxLength; + glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &maxLength ); + char *log = (char*)malloc( maxLength ); + glGetShaderInfoLog( shader, maxLength, &maxLength, log ); + + printf( "Error in shader: %s\n%s\n%s\n", log, shaderStrings[0], shaderStrings[1] ); + exit( 1 ); + } + + return shader; +} + +static GLuint shader_load( const char *shaderContents ) +{ + GLuint result; + GLuint vert = shader_compile( shaderContents, strlen( shaderContents ), GL_VERTEX_SHADER ); + GLuint frag = shader_compile( shaderContents, strlen( shaderContents ), GL_FRAGMENT_SHADER ); + + GLuint ref = glCreateProgram(); + glAttachShader( ref, vert ); + glAttachShader( ref, frag ); + + glLinkProgram ( ref ); + glDetachShader( ref, vert ); + glDetachShader( ref, frag ); + result = ref; + + return result; +} + +static void gl33core_init(RenderState *renderState, uint8_t *marioTexture) +{ + load_collision_mesh( &renderState->collision ); + renderState->world_shader = shader_load( WORLD_SHADER ); + renderState->mario_shader = shader_load( MARIO_SHADER ); + + glEnable( GL_CULL_FACE ); + glCullFace( GL_BACK ); + glClearColor( 0.2f, 0.2f, 0.2f, 1.0f ); + glDepthMask( GL_TRUE ); + glDepthFunc( GL_LEQUAL ); + glEnable( GL_DEPTH_TEST ); + + glGenTextures( 1, &renderState->mario_texture ); + glBindTexture( GL_TEXTURE_2D, renderState->mario_texture ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture); +} + +static void gl33core_draw(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo) +{ + update_mario_mesh( &renderState->mario, marioGeo ); + + mat4 model, view, projection; + glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection ); + glm_translate( view, (float*)camPos ); + glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view ); + glm_mat4_identity( model ); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glUseProgram( renderState->world_shader ); + glBindVertexArray( renderState->collision.vao ); + glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "model" ), 1, GL_FALSE, (GLfloat*)model ); + glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "view" ), 1, GL_FALSE, (GLfloat*)view ); + glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection ); + glDrawElements( GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index ); + + glUseProgram( renderState->mario_shader ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, renderState->mario_texture ); + glBindVertexArray( renderState->mario.vao ); + glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "view" ), 1, GL_FALSE, (GLfloat*)view ); + glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection ); + glUniform1i( glGetUniformLocation( renderState->mario_shader, "marioTex" ), 0 ); + glDrawElements( GL_TRIANGLES, renderState->mario.num_vertices, GL_UNSIGNED_SHORT, renderState->mario.index ); +} + +struct Renderer gl33core_renderer = { + gl33core_init, + gl33core_draw +}; diff --git a/test/gl33core/gl33core_renderer.h b/test/gl33core/gl33core_renderer.h new file mode 100644 index 0000000..58ea14e --- /dev/null +++ b/test/gl33core/gl33core_renderer.h @@ -0,0 +1,6 @@ +#ifndef GL33CORE_RENDERER_H +#define GL33CORE_RENDERER_H + +extern struct Renderer gl33core_renderer; + +#endif diff --git a/test/renderer.h b/test/renderer.h new file mode 100644 index 0000000..f6f23fb --- /dev/null +++ b/test/renderer.h @@ -0,0 +1,57 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include +#include +#include + +#include "../src/libsm64.h" + +#include "context.h" +#include "cglm.h" + +typedef struct CollisionMesh +{ + size_t num_vertices; + float *position; + float *normal; + float *color; + uint16_t *index; + + GLuint vao; + GLuint position_buffer; + GLuint normal_buffer; +} +CollisionMesh; + +typedef struct MarioMesh +{ + size_t num_vertices; + uint16_t *index; + + GLuint vao; + GLuint position_buffer; + GLuint normal_buffer; + GLuint color_buffer; + GLuint uv_buffer; +} +MarioMesh; + +typedef struct RenderState +{ + CollisionMesh collision; + MarioMesh mario; + GLuint world_shader; + GLuint mario_shader; + GLuint mario_texture; +} +RenderState; + + +struct Renderer +{ + void (*init)(RenderState *renderState, uint8_t *marioTexture); + void (*draw)(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo); +}; + +#endif From d013f61f886df9d234539ba7005c896572d4710d Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:32:15 -0400 Subject: [PATCH 06/19] get rid of implicit declaration warning --- test/audio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/audio.c b/test/audio.c index 071d77f..db37946 100644 --- a/test/audio.c +++ b/test/audio.c @@ -5,6 +5,7 @@ #include #include +#include "../src/libsm64.h" #include "context.h" static SDL_AudioDeviceID dev; From 6e8aa3dd912cbd72c642e7c352f451a48e73ad52 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:34:01 -0400 Subject: [PATCH 07/19] add gl renderers and audio sources to makefile also suppress unused function warning (cglm.h) and allow using 'make run' on windows --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c3711cb..ab861aa 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ else CC := cc LDFLAGS := -lm -shared endif -CFLAGS := -g -Wall -fPIC -DSM64_LIB_EXPORT -DGBI_FLOATS -DVERSION_US -DNO_SEGMENTED_MEMORY +CFLAGS := -g -Wall -Wno-unused-function -fPIC -DSM64_LIB_EXPORT -DGBI_FLOATS -DVERSION_US -DNO_SEGMENTED_MEMORY SRC_DIRS := src src/decomp src/decomp/engine src/decomp/include/PR src/decomp/game src/decomp/pc src/decomp/pc/audio src/decomp/mario src/decomp/tools src/decomp/audio BUILD_DIR := build @@ -26,7 +26,7 @@ C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) $(C_IMPORTED) O_FILES := $(foreach file,$(C_FILES),$(BUILD_DIR)/$(file:.c=.o)) DEP_FILES := $(O_FILES:.o=.d) -TEST_SRCS := test/main.c test/context.c test/level.c +TEST_SRCS := test/main.c test/context.c test/level.c test/audio.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c TEST_OBJS := $(foreach file,$(TEST_SRCS),$(BUILD_DIR)/$(file:.c=.o)) ifeq ($(OS),Windows_NT) @@ -34,7 +34,7 @@ ifeq ($(OS),Windows_NT) TEST_FILE := $(DIST_DIR)/run-test.exe endif -DUMMY != mkdir -p $(ALL_DIRS) build/test src/decomp/mario $(DIST_DIR)/include +DUMMY != mkdir -p $(ALL_DIRS) build/test build/test/gl33core build/test/gl20 src/decomp/mario $(DIST_DIR)/include $(filter-out src/decomp/mario/geo.inc.c,$(IMPORTED)): src/decomp/mario/geo.inc.c @@ -73,7 +73,11 @@ lib: $(LIB_FILE) $(LIB_H_FILE) test: $(TEST_FILE) $(LIB_H_FILE) run: test +ifeq ($(OS),Windows_NT) + cd dist && ./run-test +else ./$(TEST_FILE) +endif clean: rm -rf $(BUILD_DIR) $(DIST_DIR) $(TEST_FILE) From c305f282de439ef5523ddc092437052e2a934ad9 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:35:28 -0400 Subject: [PATCH 08/19] context_init args for GL ver and init SDL audio --- test/context.c | 15 +++++++-------- test/context.h | 7 +++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/test/context.c b/test/context.c index 9b5f6c1..81051c5 100644 --- a/test/context.c +++ b/test/context.c @@ -8,16 +8,15 @@ static SDL_GameController *s_controller; static int s_windowWidth; static int s_windowHeight; -void context_init( const char *title, int width, int height ) +void context_init( const char *title, int width, int height, int major, int minor ) { - if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ) goto err; + if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO ) < 0 ) goto err; - SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 ); - SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + int profile = (major < 3) ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY : SDL_GL_CONTEXT_PROFILE_CORE; + + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, major ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, profile ); SDL_GL_SetSwapInterval( 1 ); s_windowWidth = width; diff --git a/test/context.h b/test/context.h index fc7ea51..588e31f 100644 --- a/test/context.h +++ b/test/context.h @@ -8,13 +8,16 @@ #elif _WIN32 # define HAVE_M_PI # include -# include +# include #else # include # include #endif -extern void context_init( const char *title, int width, int height ); +extern int WINDOW_WIDTH; +extern int WINDOW_HEIGHT; + +extern void context_init( const char *title, int width, int height, int major, int minor ); extern bool context_flip_frame_poll_events( void ); extern SDL_GameController *context_get_controller( void ); extern void context_terminate( void ); \ No newline at end of file From 986ce5f106d72dfd097f667e60c594c507298848 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 27 Dec 2022 21:35:57 -0400 Subject: [PATCH 09/19] main.c lots of changes --- test/main.c | 495 +++++++++++++++------------------------------------- 1 file changed, 141 insertions(+), 354 deletions(-) diff --git a/test/main.c b/test/main.c index b06e8ab..6a2c948 100644 --- a/test/main.c +++ b/test/main.c @@ -5,149 +5,22 @@ #include #include #include -#include +#include +#include +#include #include "../src/libsm64.h" -#include "cglm.h" -#include "ns_clock.h" +#define SDL_MAIN_HANDLED +#include "audio.h" #include "level.h" #include "context.h" +#include "renderer.h" +#include "gl33core/gl33core_renderer.h" +#include "gl20/gl20_renderer.h" -static const int WINDOW_WIDTH = 1280; -static const int WINDOW_HEIGHT = 800; - -typedef struct CollisionMesh -{ - size_t num_vertices; - float *position; - float *normal; - uint16_t *index; - - GLuint vao; - GLuint position_buffer; - GLuint normal_buffer; -} -CollisionMesh; - -typedef struct MarioMesh -{ - size_t num_vertices; - uint16_t *index; - - GLuint vao; - GLuint position_buffer; - GLuint normal_buffer; - GLuint color_buffer; - GLuint uv_buffer; -} -MarioMesh; - -typedef struct RenderState -{ - CollisionMesh collision; - MarioMesh mario; - GLuint world_shader; - GLuint mario_shader; - GLuint mario_texture; -} -RenderState; - -static const char *MARIO_SHADER = -"\n uniform mat4 view;" -"\n uniform mat4 projection;" -"\n uniform sampler2D marioTex;" -"\n " -"\n v2f vec3 v_color;" -"\n v2f vec3 v_normal;" -"\n v2f vec3 v_light;" -"\n v2f vec2 v_uv;" -"\n " -"\n #ifdef VERTEX" -"\n " -"\n layout(location = 0) in vec3 position;" -"\n layout(location = 1) in vec3 normal;" -"\n layout(location = 2) in vec3 color;" -"\n layout(location = 3) in vec2 uv;" -"\n " -"\n void main()" -"\n {" -"\n v_color = color;" -"\n v_normal = normal;" -"\n v_light = transpose( mat3( view )) * normalize( vec3( 1 ));" -"\n v_uv = uv;" -"\n " -"\n gl_Position = projection * view * vec4( position, 1. );" -"\n }" -"\n " -"\n #endif" -"\n #ifdef FRAGMENT" -"\n " -"\n out vec4 color;" -"\n " -"\n void main() " -"\n {" -"\n float light = .5 + .5 * clamp( dot( v_normal, v_light ), 0., 1. );" -"\n vec4 texColor = texture2D( marioTex, v_uv );" -"\n vec3 mainColor = mix( v_color, texColor.rgb, texColor.a ); // v_uv.x >= 0. ? texColor.a : 0. );" -"\n color = vec4( mainColor * light, 1 );" -"\n }" -"\n " -"\n #endif" -; -static const char *WORLD_SHADER = -"\n uniform mat4 model;" -"\n uniform mat4 view;" -"\n uniform mat4 projection;" -"\n uniform sampler2D tex;" -"\n " -"\n v2f vec3 v_normal;" -"\n v2f vec3 v_worldPos;" -"\n " -"\n #ifdef VERTEX" -"\n " -"\n layout(location = 0) in vec3 position;" -"\n layout(location = 1) in vec3 normal;" -"\n " -"\n void main()" -"\n {" -"\n v_normal = inverse(mat3(model)) * normal;" -"\n vec4 worldPos4 = model * vec4(position, 1.);" -"\n v_worldPos = worldPos4.xyz;" -"\n gl_Position = projection * view * worldPos4;" -"\n }" -"\n " -"\n #endif" -"\n #ifdef FRAGMENT" -"\n " -"\n vec3 tri( vec3 x )" -"\n {" -"\n return abs(x-floor(x)-.5);" -"\n } " -"\n float surfFunc( vec3 p )" -"\n {" -"\n float n = dot(tri(p*.15 + tri(p.yzx*.075)), vec3(.444));" -"\n p = p*1.5773 - n;" -"\n p.yz = vec2(p.y + p.z, p.z - p.y) * .866;" -"\n p.xz = vec2(p.x + p.z, p.z - p.x) * .866;" -"\n n += dot(tri(p*.225 + tri(p.yzx*.1125)), vec3(.222)); " -"\n return abs(n-.5)*1.9 + (1.-abs(sin(n*9.)))*.05;" -"\n }" -"\n " -"\n const vec3 light_x = vec3(-1.0, 0.4, 0.9);" -"\n " -"\n out vec4 color;" -"\n " -"\n void main() " -"\n {" -"\n float surfy = surfFunc( v_worldPos / 50. );" -"\n float brightness = smoothstep( .2, .3, surfy );" -"\n " -"\n color = vec4( (0.5 + 0.25 * brightness) * (.5+.5*v_normal), 1 );" -"\n }" -"\n " -"\n #endif" -; +int WINDOW_WIDTH = 1280; +int WINDOW_HEIGHT = 800; uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength ) { @@ -168,206 +41,6 @@ uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength ) return buffer; } -static GLuint shader_compile( const char *shaderContents, size_t shaderContentsLength, GLenum shaderType ) -{ - const GLchar *shaderDefine = shaderType == GL_VERTEX_SHADER - ? "\n#version 410\n#define VERTEX \n#define v2f out\n" - : "\n#version 410\n#define FRAGMENT\n#define v2f in \n"; - - const GLchar *shaderStrings[2] = { shaderDefine, shaderContents }; - GLint shaderStringLengths[2] = { strlen( shaderDefine ), (GLint)shaderContentsLength }; - - GLuint shader = glCreateShader( shaderType ); - glShaderSource( shader, 2, shaderStrings, shaderStringLengths ); - glCompileShader( shader ); - - GLint isCompiled; - glGetShaderiv( shader, GL_COMPILE_STATUS, &isCompiled ); - if( isCompiled == GL_FALSE ) - { - GLint maxLength; - glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &maxLength ); - char *log = (char*)malloc( maxLength ); - glGetShaderInfoLog( shader, maxLength, &maxLength, log ); - - printf( "Error in shader: %s\n%s\n%s\n", log, shaderStrings[0], shaderStrings[1] ); - exit( 1 ); - } - - return shader; -} - -static GLuint shader_load( const char *shaderContents ) -{ - GLuint result; - GLuint vert = shader_compile( shaderContents, strlen( shaderContents ), GL_VERTEX_SHADER ); - GLuint frag = shader_compile( shaderContents, strlen( shaderContents ), GL_FRAGMENT_SHADER ); - - GLuint ref = glCreateProgram(); - glAttachShader( ref, vert ); - glAttachShader( ref, frag ); - glLinkProgram ( ref ); - glDetachShader( ref, vert ); - glDetachShader( ref, frag ); - result = ref; - - return result; -} - -static void load_collision_mesh( CollisionMesh *mesh ) -{ - mesh->num_vertices = 3 * surfaces_count; - mesh->position = malloc( sizeof( float ) * surfaces_count * 9 ); - mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 ); - mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 ); - - for( size_t i = 0; i < surfaces_count; ++i ) - { - const struct SM64Surface *surf = &surfaces[i]; - - float x1 = mesh->position[9*i+0] = surf->vertices[0][0]; - float y1 = mesh->position[9*i+1] = surf->vertices[0][1]; - float z1 = mesh->position[9*i+2] = surf->vertices[0][2]; - float x2 = mesh->position[9*i+3] = surf->vertices[1][0]; - float y2 = mesh->position[9*i+4] = surf->vertices[1][1]; - float z2 = mesh->position[9*i+5] = surf->vertices[1][2]; - float x3 = mesh->position[9*i+6] = surf->vertices[2][0]; - float y3 = mesh->position[9*i+7] = surf->vertices[2][1]; - float z3 = mesh->position[9*i+8] = surf->vertices[2][2]; - - float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2); - float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2); - float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2); - float mag = sqrtf(nx * nx + ny * ny + nz * nz); - nx /= mag; - ny /= mag; - nz /= mag; - - mesh->normal[9*i+0] = nx; - mesh->normal[9*i+1] = ny; - mesh->normal[9*i+2] = nz; - mesh->normal[9*i+3] = nx; - mesh->normal[9*i+4] = ny; - mesh->normal[9*i+5] = nz; - mesh->normal[9*i+6] = nx; - mesh->normal[9*i+7] = ny; - mesh->normal[9*i+8] = nz; - - mesh->index[3*i+0] = 3*i+0; - mesh->index[3*i+1] = 3*i+1; - mesh->index[3*i+2] = 3*i+2; - } - - glGenVertexArrays( 1, &mesh->vao ); - glBindVertexArray( mesh->vao ); - - #define X( loc, buff, arr, type ) do { \ - glGenBuffers( 1, &buff ); \ - glBindBuffer( GL_ARRAY_BUFFER, buff ); \ - glBufferData( GL_ARRAY_BUFFER, mesh->num_vertices*sizeof( type ), arr, GL_STATIC_DRAW ); \ - glEnableVertexAttribArray( loc ); \ - glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \ - } while( 0 ) - - X( 0, mesh->position_buffer, mesh->position, vec3 ); - X( 1, mesh->normal_buffer, mesh->normal, vec3 ); - - #undef X -} - -static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) -{ - mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) ); - for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i ) - mesh->index[i] = i; - - mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES; - - glGenVertexArrays( 1, &mesh->vao ); - glBindVertexArray( mesh->vao ); - - #define X( loc, buff, arr, type ) do { \ - glGenBuffers( 1, &buff ); \ - glBindBuffer( GL_ARRAY_BUFFER, buff ); \ - glBufferData( GL_ARRAY_BUFFER, sizeof( type ) * 3 * SM64_GEO_MAX_TRIANGLES, arr, GL_DYNAMIC_DRAW ); \ - glEnableVertexAttribArray( loc ); \ - glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \ - } while( 0 ) - - X( 0, mesh->position_buffer, marioGeo->position, vec3 ); - X( 1, mesh->normal_buffer, marioGeo->normal, vec3 ); - X( 2, mesh->color_buffer, marioGeo->color, vec3 ); - X( 3, mesh->uv_buffer, marioGeo->uv, vec2 ); - - #undef X -} - -static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) -{ - if( mesh->index == NULL ) - load_mario_mesh( mesh, marioGeo ); - - mesh->num_vertices = 3 * marioGeo->numTrianglesUsed; - - glBindBuffer( GL_ARRAY_BUFFER, mesh->position_buffer ); - glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->position, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, mesh->normal_buffer ); - glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->normal, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, mesh->color_buffer ); - glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->color, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, mesh->uv_buffer ); - glBufferData( GL_ARRAY_BUFFER, sizeof( vec2 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->uv, GL_DYNAMIC_DRAW ); -} - -void render_state_init( RenderState *renderState, uint8_t *marioTexture ) -{ - load_collision_mesh( &renderState->collision ); - renderState->world_shader = shader_load( WORLD_SHADER ); - renderState->mario_shader = shader_load( MARIO_SHADER ); - - glEnable( GL_CULL_FACE ); - glCullFace( GL_BACK ); - glClearColor( 0.2f, 0.2f, 0.2f, 1.0f ); - glEnable( GL_DEPTH_TEST ); - - glGenTextures( 1, &renderState->mario_texture ); - glBindTexture( GL_TEXTURE_2D, renderState->mario_texture ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture); -} - -void render_draw( RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo ) -{ - update_mario_mesh( &renderState->mario, marioGeo ); - - mat4 model, view, projection; - glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection ); - glm_translate( view, (float*)camPos ); - glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view ); - glm_mat4_identity( model ); - - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - glUseProgram( renderState->world_shader ); - glBindVertexArray( renderState->collision.vao ); - glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "model" ), 1, GL_FALSE, (GLfloat*)model ); - glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "view" ), 1, GL_FALSE, (GLfloat*)view ); - glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection ); - glDrawElements( GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index ); - - glUseProgram( renderState->mario_shader ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, renderState->mario_texture ); - glBindVertexArray( renderState->mario.vao ); - glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "view" ), 1, GL_FALSE, (GLfloat*)view ); - glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection ); - glUniform1i( glGetUniformLocation( renderState->mario_shader, "marioTex" ), 0 ); - glDrawElements( GL_TRIANGLES, renderState->mario.num_vertices, GL_UNSIGNED_SHORT, renderState->mario.index ); -} - static float read_axis( int16_t val ) { float result = (float)val / 32767.0f; @@ -378,6 +51,11 @@ static float read_axis( int16_t val ) return result > 0.0f ? (result - 0.2f) / 0.8f : (result + 0.2f) / 0.8f; } +float lerp(float a, float b, float amount) +{ + return a + (b - a) * amount; +} + int main( void ) { size_t romSize; @@ -394,6 +72,7 @@ int main( void ) sm64_global_terminate(); sm64_global_init( rom, texture ); + sm64_audio_init(rom); sm64_static_surfaces_load( surfaces, surfaces_count ); uint32_t marioId = sm64_mario_create( 0, 1000, 0 ); @@ -404,50 +83,158 @@ int main( void ) vec3 cameraPos = { 0, 0, 0 }; float cameraRot = 0.0f; - context_init( "libsm64", WINDOW_WIDTH, WINDOW_HEIGHT ); - render_state_init( &renderState, texture ); + struct Renderer *renderer; - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 0; + int major, minor, selection = 0; + printf("Select OpenGL version\n1. OpenGL 3.3 Core\n2. OpenGL 2.0\n> "); + scanf("%d", &selection); + if (selection == 2) + { + printf("Launching with OpenGL 2.0\n\n"); + major = 2; minor = 0; + renderer = &gl20_renderer; + } + else + { + printf("Launching with OpenGL 3.3 Core\n\n"); + major = 3; minor = 3; + renderer = &gl33core_renderer; + } + + printf("Select window resolution\n1. 1280x800\n2. 800x600\n> "); + scanf("%d", &selection); + if (selection == 2) + { + printf("Launching in 800x600\n"); + WINDOW_WIDTH = 800; WINDOW_HEIGHT = 600; + } + else + printf("Launching in 1280x600\n"); + + context_init( "libsm64", WINDOW_WIDTH, WINDOW_HEIGHT, major, minor ); + renderer->init( &renderState, texture ); struct SM64MarioInputs marioInputs; struct SM64MarioState marioState; struct SM64MarioGeometryBuffers marioGeometry; + // interpolation + float lastPos[3], currPos[3]; + float lastGeoPos[9 * SM64_GEO_MAX_TRIANGLES], currGeoPos[9 * SM64_GEO_MAX_TRIANGLES]; + marioGeometry.position = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); marioGeometry.color = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); marioGeometry.normal = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); marioGeometry.uv = malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES ); + marioGeometry.numTrianglesUsed = 0; + + float tick = 0, dt = 0; + + audio_init(); do { - uint64_t frameTopTime = ns_clock(); + uint64_t start = SDL_GetPerformanceCounter(); SDL_GameController *controller = context_get_controller(); - float x_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTX )); - float y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY )); - float x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX )); + float x_axis, y_axis, x0_axis; - cameraRot += 0.1f * x0_axis; + if (!controller) // keyboard + { + const Uint8* state = SDL_GetKeyboardState(NULL); + + float dir; + float spd = 0; + if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_RIGHT]) + { + dir = -M_PI * 0.25f; + spd = 1; + } + else if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_LEFT]) + { + dir = -M_PI * 0.75f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_RIGHT]) + { + dir = M_PI * 0.25f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_LEFT]) + { + dir = M_PI * 0.75f; + spd = 1; + } + else if (state[SDL_SCANCODE_UP]) + { + dir = -M_PI * 0.5f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN]) + { + dir = M_PI * 0.5f; + spd = 1; + } + else if (state[SDL_SCANCODE_LEFT]) + { + dir = M_PI; + spd = 1; + } + else if (state[SDL_SCANCODE_RIGHT]) + { + dir = 0; + spd = 1; + } + + x_axis = cosf(dir) * spd; + y_axis = sinf(dir) * spd; + x0_axis = state[SDL_SCANCODE_LSHIFT] ? 1 : state[SDL_SCANCODE_RSHIFT] ? -1 : 0; + + marioInputs.buttonA = state[SDL_SCANCODE_X]; + marioInputs.buttonB = state[SDL_SCANCODE_C]; + marioInputs.buttonZ = state[SDL_SCANCODE_Z]; + } + else + { + x_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTX )); + y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY )); + x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX )); + + marioInputs.buttonA = SDL_GameControllerGetButton( controller, 0 ); + marioInputs.buttonB = SDL_GameControllerGetButton( controller, 2 ); + marioInputs.buttonZ = SDL_GameControllerGetButton( controller, 9 ); + } + + cameraRot += x0_axis * dt * 2; cameraPos[0] = marioState.position[0] + 1000.0f * cosf( cameraRot ); cameraPos[1] = marioState.position[1] + 200.0f; cameraPos[2] = marioState.position[2] + 1000.0f * sinf( cameraRot ); - marioInputs.buttonA = SDL_GameControllerGetButton( controller, 0 ); - marioInputs.buttonB = SDL_GameControllerGetButton( controller, 2 ); - marioInputs.buttonZ = SDL_GameControllerGetButton( controller, 9 ); marioInputs.camLookX = marioState.position[0] - cameraPos[0]; marioInputs.camLookZ = marioState.position[2] - cameraPos[2]; marioInputs.stickX = x_axis; marioInputs.stickY = y_axis; - sm64_mario_tick( marioId, &marioInputs, &marioState, &marioGeometry ); + while (tick >= 1.f/30) + { + memcpy(lastPos, currPos, sizeof(currPos)); + memcpy(lastGeoPos, currGeoPos, sizeof(currGeoPos)); - render_draw( &renderState, cameraPos, &marioState, &marioGeometry ); + tick -= 1.f/30; + sm64_mario_tick( marioId, &marioInputs, &marioState, &marioGeometry ); - ts.tv_nsec = 33333333 - (ns_clock() - frameTopTime); - nanosleep( &ts, &ts ); + memcpy(currPos, marioState.position, sizeof(currPos)); + memcpy(currGeoPos, marioGeometry.position, sizeof(currGeoPos)); + } + + for (int i=0; i<3; i++) marioState.position[i] = lerp(lastPos[i], currPos[i], tick / (1.f/30)); + for (int i=0; idraw( &renderState, cameraPos, &marioState, &marioGeometry ); + + uint64_t end = SDL_GetPerformanceCounter(); + dt = (float)(end-start) / (float)SDL_GetPerformanceFrequency(); + tick += dt; } while( context_flip_frame_poll_events() ); From ef13bae2fc5d124f7e1908bfdb5fcf4b2688e962 Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Thu, 12 Jan 2023 13:44:46 -0400 Subject: [PATCH 10/19] don't init audio in context.c --- test/context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/context.c b/test/context.c index 81051c5..1e82039 100644 --- a/test/context.c +++ b/test/context.c @@ -10,7 +10,7 @@ static int s_windowHeight; void context_init( const char *title, int width, int height, int major, int minor ) { - if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO ) < 0 ) goto err; + if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ) goto err; int profile = (major < 3) ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY : SDL_GL_CONTEXT_PROFILE_CORE; @@ -111,4 +111,4 @@ void context_terminate( void ) SDL_Quit(); s_sdlWindow = NULL; -} \ No newline at end of file +} From 6e5accb909469238e8116d54517483cd2e78c8ed Mon Sep 17 00:00:00 2001 From: headshot2017 <> Date: Thu, 12 Jan 2023 13:44:50 -0400 Subject: [PATCH 11/19] turn audio.c and main.c into CPP files fixes crash when trying to init audio on linux --- Makefile | 15 +++++++++++---- test/{audio.c => audio.cpp} | 11 +++++++++-- test/{main.c => main.cpp} | 24 +++++++++++++----------- test/renderer.h | 8 ++++++++ 4 files changed, 41 insertions(+), 17 deletions(-) rename test/{audio.c => audio.cpp} (85%) rename test/{main.c => main.cpp} (90%) diff --git a/Makefile b/Makefile index ab861aa..010a61b 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,11 @@ default: lib ifdef LIBSM64_MUSL CC := musl-gcc + CXX := musl-g++ LDFLAGS := -lm -static -shared else CC := cc + CXX := c++ LDFLAGS := -lm -shared endif CFLAGS := -g -Wall -Wno-unused-function -fPIC -DSM64_LIB_EXPORT -DGBI_FLOATS -DVERSION_US -DNO_SEGMENTED_MEMORY @@ -26,8 +28,9 @@ C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) $(C_IMPORTED) O_FILES := $(foreach file,$(C_FILES),$(BUILD_DIR)/$(file:.c=.o)) DEP_FILES := $(O_FILES:.o=.d) -TEST_SRCS := test/main.c test/context.c test/level.c test/audio.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c -TEST_OBJS := $(foreach file,$(TEST_SRCS),$(BUILD_DIR)/$(file:.c=.o)) +TEST_SRCS_C := test/context.c test/level.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c +TEST_SRCS_CPP := test/main.cpp test/audio.cpp +TEST_OBJS := $(foreach file,$(TEST_SRCS_C),$(BUILD_DIR)/$(file:.c=.o)) $(foreach file,$(TEST_SRCS_CPP),$(BUILD_DIR)/$(file:.cpp=.o)) ifeq ($(OS),Windows_NT) LIB_FILE := $(DIST_DIR)/sm64.dll @@ -45,6 +48,10 @@ $(BUILD_DIR)/%.o: %.c $(IMPORTED) @$(CC) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/$*.d $< $(CC) -c $(CFLAGS) -I src/decomp/include -o $@ $< +$(BUILD_DIR)/%.o: %.cpp $(IMPORTED) + @$(CXX) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/$*.d $< + $(CXX) -c $(CFLAGS) -I src/decomp/include -o $@ $< + $(LIB_FILE): $(O_FILES) $(CC) $(LDFLAGS) -o $@ $^ @@ -55,7 +62,7 @@ $(LIB_H_FILE): src/libsm64.h test/level.c test/level.h: ./import-test-collision.py ./import-test-collision.py -test/main.c: test/level.h +test/main.cpp: test/level.h $(BUILD_DIR)/test/%.o: test/%.c @$(CC) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/test/$*.d $< @@ -65,7 +72,7 @@ $(TEST_FILE): $(LIB_FILE) $(TEST_OBJS) ifeq ($(OS),Windows_NT) $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lglew32 -lopengl32 -lSDL2 -lSDL2main -lm else - $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm + $(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm -lpthread endif lib: $(LIB_FILE) $(LIB_H_FILE) diff --git a/test/audio.c b/test/audio.cpp similarity index 85% rename from test/audio.c rename to test/audio.cpp index db37946..fae4574 100644 --- a/test/audio.c +++ b/test/audio.cpp @@ -5,8 +5,10 @@ #include #include +extern "C" { #include "../src/libsm64.h" #include "context.h" +} static SDL_AudioDeviceID dev; @@ -24,7 +26,7 @@ void* audio_thread(void* keepAlive) // from https://github.com/ckosmic/libsm64/blob/audio/src/libsm64.c#L535-L555 // except keepAlive is a null pointer here, so don't use it - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); long long currentTime = timeInMilliseconds(); @@ -50,6 +52,11 @@ void* audio_thread(void* keepAlive) void audio_init() { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + fprintf(stderr, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError()); + return; + } + SDL_AudioSpec want, have; SDL_zero(want); want.freq = 32000; @@ -65,6 +72,6 @@ void audio_init() SDL_PauseAudioDevice(dev, 0); // it's best to run audio in a separate thread - pthread_create(&gSoundThread, NULL, audio_thread, NULL); + pthread_create(&gSoundThread, NULL, audio_thread, NULL); } diff --git a/test/main.c b/test/main.cpp similarity index 90% rename from test/main.c rename to test/main.cpp index 6a2c948..0b13dbd 100644 --- a/test/main.c +++ b/test/main.cpp @@ -9,15 +9,17 @@ #include #include +extern "C" { #include "../src/libsm64.h" - #define SDL_MAIN_HANDLED -#include "audio.h" #include "level.h" #include "context.h" #include "renderer.h" #include "gl33core/gl33core_renderer.h" #include "gl20/gl20_renderer.h" +} + +#include "audio.h" int WINDOW_WIDTH = 1280; int WINDOW_HEIGHT = 800; @@ -31,7 +33,7 @@ uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength ) fseek( f, 0, SEEK_END ); size_t length = (size_t)ftell( f ); rewind( f ); - uint8_t *buffer = malloc( length + 1 ); + uint8_t *buffer = (uint8_t*)malloc( length + 1 ); fread( buffer, 1, length, f ); buffer[length] = 0; fclose( f ); @@ -68,7 +70,7 @@ int main( void ) return 1; } - uint8_t *texture = malloc( 4 * SM64_TEXTURE_WIDTH * SM64_TEXTURE_HEIGHT ); + uint8_t *texture = (uint8_t*)malloc( 4 * SM64_TEXTURE_WIDTH * SM64_TEXTURE_HEIGHT ); sm64_global_terminate(); sm64_global_init( rom, texture ); @@ -122,10 +124,10 @@ int main( void ) float lastPos[3], currPos[3]; float lastGeoPos[9 * SM64_GEO_MAX_TRIANGLES], currGeoPos[9 * SM64_GEO_MAX_TRIANGLES]; - marioGeometry.position = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); - marioGeometry.color = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); - marioGeometry.normal = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); - marioGeometry.uv = malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES ); + marioGeometry.position = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); + marioGeometry.color = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); + marioGeometry.normal = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES ); + marioGeometry.uv = (float*)malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES ); marioGeometry.numTrianglesUsed = 0; float tick = 0, dt = 0; @@ -200,9 +202,9 @@ int main( void ) y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY )); x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX )); - marioInputs.buttonA = SDL_GameControllerGetButton( controller, 0 ); - marioInputs.buttonB = SDL_GameControllerGetButton( controller, 2 ); - marioInputs.buttonZ = SDL_GameControllerGetButton( controller, 9 ); + marioInputs.buttonA = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)0 ); + marioInputs.buttonB = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)2 ); + marioInputs.buttonZ = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)9 ); } cameraRot += x0_axis * dt * 2; diff --git a/test/renderer.h b/test/renderer.h index f6f23fb..00f24e3 100644 --- a/test/renderer.h +++ b/test/renderer.h @@ -5,8 +5,16 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #include "../src/libsm64.h" +#ifdef __cplusplus +} +#endif + #include "context.h" #include "cglm.h" From 40215dacc1f96a20c1ca3303420e760fe27e1a1e Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Thu, 12 Jan 2023 16:52:10 -0400 Subject: [PATCH 12/19] use SDL_GameControllerButton enum instead of int casts --- test/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 0b13dbd..2f3dd79 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -202,9 +202,9 @@ int main( void ) y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY )); x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX )); - marioInputs.buttonA = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)0 ); - marioInputs.buttonB = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)2 ); - marioInputs.buttonZ = SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)9 ); + marioInputs.buttonA = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_A ); + marioInputs.buttonB = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_X ); + marioInputs.buttonZ = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER ); } cameraRot += x0_axis * dt * 2; From 8eace1b904aec0f72436a9fc4cad683cda46ced4 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Thu, 12 Jan 2023 16:55:27 -0400 Subject: [PATCH 13/19] cleanup tabs -> spaces --- test/main.cpp | 102 +++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 2f3dd79..08f75c0 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -96,7 +96,7 @@ int main( void ) major = 2; minor = 0; renderer = &gl20_renderer; } - else + else { printf("Launching with OpenGL 3.3 Core\n\n"); major = 3; minor = 3; @@ -108,9 +108,9 @@ int main( void ) if (selection == 2) { printf("Launching in 800x600\n"); - WINDOW_WIDTH = 800; WINDOW_HEIGHT = 600; + WINDOW_WIDTH = 800; WINDOW_HEIGHT = 600; } - else + else printf("Launching in 1280x600\n"); context_init( "libsm64", WINDOW_WIDTH, WINDOW_HEIGHT, major, minor ); @@ -139,7 +139,7 @@ int main( void ) uint64_t start = SDL_GetPerformanceCounter(); SDL_GameController *controller = context_get_controller(); - float x_axis, y_axis, x0_axis; + float x_axis, y_axis, x0_axis; if (!controller) // keyboard { @@ -147,57 +147,57 @@ int main( void ) float dir; float spd = 0; - if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_RIGHT]) - { - dir = -M_PI * 0.25f; - spd = 1; - } - else if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_LEFT]) - { - dir = -M_PI * 0.75f; - spd = 1; - } - else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_RIGHT]) - { - dir = M_PI * 0.25f; - spd = 1; - } - else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_LEFT]) - { - dir = M_PI * 0.75f; - spd = 1; - } - else if (state[SDL_SCANCODE_UP]) - { - dir = -M_PI * 0.5f; - spd = 1; - } - else if (state[SDL_SCANCODE_DOWN]) - { - dir = M_PI * 0.5f; - spd = 1; - } - else if (state[SDL_SCANCODE_LEFT]) - { - dir = M_PI; - spd = 1; - } - else if (state[SDL_SCANCODE_RIGHT]) - { - dir = 0; - spd = 1; - } + if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_RIGHT]) + { + dir = -M_PI * 0.25f; + spd = 1; + } + else if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_LEFT]) + { + dir = -M_PI * 0.75f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_RIGHT]) + { + dir = M_PI * 0.25f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_LEFT]) + { + dir = M_PI * 0.75f; + spd = 1; + } + else if (state[SDL_SCANCODE_UP]) + { + dir = -M_PI * 0.5f; + spd = 1; + } + else if (state[SDL_SCANCODE_DOWN]) + { + dir = M_PI * 0.5f; + spd = 1; + } + else if (state[SDL_SCANCODE_LEFT]) + { + dir = M_PI; + spd = 1; + } + else if (state[SDL_SCANCODE_RIGHT]) + { + dir = 0; + spd = 1; + } - x_axis = cosf(dir) * spd; - y_axis = sinf(dir) * spd; + x_axis = cosf(dir) * spd; + y_axis = sinf(dir) * spd; x0_axis = state[SDL_SCANCODE_LSHIFT] ? 1 : state[SDL_SCANCODE_RSHIFT] ? -1 : 0; marioInputs.buttonA = state[SDL_SCANCODE_X]; marioInputs.buttonB = state[SDL_SCANCODE_C]; marioInputs.buttonZ = state[SDL_SCANCODE_Z]; } - else - { + else + { x_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTX )); y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY )); x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX )); @@ -205,7 +205,7 @@ int main( void ) marioInputs.buttonA = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_A ); marioInputs.buttonB = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_X ); marioInputs.buttonZ = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER ); - } + } cameraRot += x0_axis * dt * 2; cameraPos[0] = marioState.position[0] + 1000.0f * cosf( cameraRot ); @@ -235,8 +235,8 @@ int main( void ) renderer->draw( &renderState, cameraPos, &marioState, &marioGeometry ); uint64_t end = SDL_GetPerformanceCounter(); - dt = (float)(end-start) / (float)SDL_GetPerformanceFrequency(); - tick += dt; + dt = (float)(end-start) / (float)SDL_GetPerformanceFrequency(); + tick += dt; } while( context_flip_frame_poll_events() ); From b79601bb8eae8dae5f9c03581fb2745af37039b8 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Mon, 23 Jan 2023 20:59:10 -0400 Subject: [PATCH 14/19] move SetSwapInterval call down --- test/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/context.c b/test/context.c index 1e82039..eca308b 100644 --- a/test/context.c +++ b/test/context.c @@ -17,7 +17,6 @@ void context_init( const char *title, int width, int height, int major, int mino SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, major ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, profile ); - SDL_GL_SetSwapInterval( 1 ); s_windowWidth = width; s_windowHeight = height; @@ -32,6 +31,7 @@ void context_init( const char *title, int width, int height, int major, int mino if( !s_sdlWindow ) goto err; s_sdlGlContext = SDL_GL_CreateContext( s_sdlWindow ); + SDL_GL_SetSwapInterval( 1 ); if( !s_sdlGlContext ) goto err; From b758c9a0377662a20bbe3da362258085e07cceb1 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Mon, 23 Jan 2023 21:11:16 -0400 Subject: [PATCH 15/19] fix deltatime calculation --- test/main.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 08f75c0..46c9482 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -130,13 +130,16 @@ int main( void ) marioGeometry.uv = (float*)malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES ); marioGeometry.numTrianglesUsed = 0; - float tick = 0, dt = 0; + float tick = 0; + uint32_t lastTicks = 0; audio_init(); do { - uint64_t start = SDL_GetPerformanceCounter(); + float dt = (SDL_GetTicks() - lastTicks) / 1000.f; + lastTicks = SDL_GetTicks(); + tick += dt; SDL_GameController *controller = context_get_controller(); float x_axis, y_axis, x0_axis; @@ -233,10 +236,6 @@ int main( void ) for (int i=0; idraw( &renderState, cameraPos, &marioState, &marioGeometry ); - - uint64_t end = SDL_GetPerformanceCounter(); - dt = (float)(end-start) / (float)SDL_GetPerformanceFrequency(); - tick += dt; } while( context_flip_frame_poll_events() ); From 405de6a367cff4e48bd92a322dff3a8c8e128cfb Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Mon, 23 Jan 2023 22:56:47 -0400 Subject: [PATCH 16/19] change lastTicks start value --- test/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main.cpp b/test/main.cpp index 46c9482..280365c 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -131,7 +131,7 @@ int main( void ) marioGeometry.numTrianglesUsed = 0; float tick = 0; - uint32_t lastTicks = 0; + uint32_t lastTicks = SDL_GetTicks(); audio_init(); From c1031ad6c6ebd17049d7bb9d6b2ebb8dd3b4c1b7 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Tue, 24 Jan 2023 00:44:04 -0400 Subject: [PATCH 17/19] don't stretch viewport when resizing --- test/context.c | 14 +++++++------- test/gl20/gl20_renderer.c | 1 - test/main.cpp | 8 +++----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/test/context.c b/test/context.c index eca308b..938114c 100644 --- a/test/context.c +++ b/test/context.c @@ -5,8 +5,8 @@ static SDL_Window *s_sdlWindow; static SDL_GLContext s_sdlGlContext; static SDL_GameController *s_controller; -static int s_windowWidth; -static int s_windowHeight; +int WINDOW_WIDTH; +int WINDOW_HEIGHT; void context_init( const char *title, int width, int height, int major, int minor ) { @@ -18,8 +18,8 @@ void context_init( const char *title, int width, int height, int major, int mino SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, profile ); - s_windowWidth = width; - s_windowHeight = height; + WINDOW_WIDTH = width; + WINDOW_HEIGHT = height; s_sdlWindow = SDL_CreateWindow( title, @@ -87,9 +87,9 @@ bool context_flip_frame_poll_events( void ) case SDL_WINDOWEVENT: if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ) { - s_windowWidth = event.window.data1; - s_windowHeight = event.window.data2; - glViewport( 0, 0, s_windowWidth, s_windowHeight ); + WINDOW_WIDTH = event.window.data1; + WINDOW_HEIGHT = event.window.data2; + glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT ); } break; } diff --git a/test/gl20/gl20_renderer.c b/test/gl20/gl20_renderer.c index cf846aa..de7773a 100644 --- a/test/gl20/gl20_renderer.c +++ b/test/gl20/gl20_renderer.c @@ -6,7 +6,6 @@ #include "../renderer.h" #include "../context.h" #include "../level.h" -#include static void load_collision_mesh( CollisionMesh *mesh ) { diff --git a/test/main.cpp b/test/main.cpp index 280365c..06852f2 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -21,9 +21,6 @@ extern "C" { #include "audio.h" -int WINDOW_WIDTH = 1280; -int WINDOW_HEIGHT = 800; - uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength ) { FILE *f = fopen( path, "rb" ); @@ -88,6 +85,7 @@ int main( void ) struct Renderer *renderer; int major, minor, selection = 0; + int w = 1280, h = 800; printf("Select OpenGL version\n1. OpenGL 3.3 Core\n2. OpenGL 2.0\n> "); scanf("%d", &selection); if (selection == 2) @@ -108,12 +106,12 @@ int main( void ) if (selection == 2) { printf("Launching in 800x600\n"); - WINDOW_WIDTH = 800; WINDOW_HEIGHT = 600; + w = 800; h = 600; } else printf("Launching in 1280x600\n"); - context_init( "libsm64", WINDOW_WIDTH, WINDOW_HEIGHT, major, minor ); + context_init( "libsm64", w, h, major, minor ); renderer->init( &renderState, texture ); struct SM64MarioInputs marioInputs; From 7b8563f6ce436ebfec153107cfdc3583f235f958 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Wed, 25 Jan 2023 23:15:22 -0400 Subject: [PATCH 18/19] add world texture to GL2.0 renderer --- test/gl20/gl20_renderer.c | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/test/gl20/gl20_renderer.c b/test/gl20/gl20_renderer.c index de7773a..d9de645 100644 --- a/test/gl20/gl20_renderer.c +++ b/test/gl20/gl20_renderer.c @@ -7,12 +7,18 @@ #include "../context.h" #include "../level.h" +GLuint worldTexture; +uint8_t *worldTextureRaw; +int worldTextureSize[2] = {256, 256}; +float *worldUv; + static void load_collision_mesh( CollisionMesh *mesh ) { mesh->num_vertices = 3 * surfaces_count; mesh->position = malloc( sizeof( float ) * surfaces_count * 9 ); mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 ); mesh->color = malloc( sizeof( float ) * surfaces_count * 9 ); + worldUv = malloc(sizeof(float) * surfaces_count * 6); mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 ); for( size_t i = 0; i < surfaces_count; ++i ) @@ -54,6 +60,23 @@ static void load_collision_mesh( CollisionMesh *mesh ) mesh->index[3*i+1] = 3*i+1; mesh->index[3*i+2] = 3*i+2; } + + for( size_t i = 0; i < surfaces_count/2; i++ ) + { + worldUv[12*i+0] = 0.f; + worldUv[12*i+1] = 0.f; + worldUv[12*i+2] = 4.f; + worldUv[12*i+3] = 0.f; + worldUv[12*i+4] = 0.f; + worldUv[12*i+5] = 4.f; + + worldUv[12*i+6] = 0.f; + worldUv[12*i+7] = 4.f; + worldUv[12*i+8] = 4.f; + worldUv[12*i+9] = 0.f; + worldUv[12*i+10] = 0.f; + worldUv[12*i+11] = 0.f; + } } static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo ) @@ -104,6 +127,33 @@ static void gl20_init(RenderState *renderState, uint8_t *marioTexture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture); + + // make a custom world texture programatically + worldTextureRaw = (uint8_t*)malloc(worldTextureSize[0] * worldTextureSize[1] * 4); + memset(worldTextureRaw, 255, worldTextureSize[0] * worldTextureSize[1] * 4); + + for (int y=0; ycollision.position); glNormalPointer(GL_FLOAT, 0, renderState->collision.normal); glColorPointer(3, GL_FLOAT, 0, renderState->collision.color); + glTexCoordPointer(2, GL_FLOAT, 0, worldUv); + + glBindTexture(GL_TEXTURE_2D, worldTexture); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); glDrawElements(GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index); // create lighting on the scene @@ -145,6 +202,7 @@ static void gl20_draw(RenderState *renderState, const vec3 camPos, const struct glEnable(GL_LIGHT0); // first, draw geometry without Mario's texture. + glBindTexture(GL_TEXTURE_2D, 0); update_mario_mesh( &renderState->mario, marioGeo ); uint32_t triangleSize = renderState->mario.num_vertices; @@ -153,7 +211,6 @@ static void gl20_draw(RenderState *renderState, const vec3 camPos, const struct // now disable the color array and enable the texture. glDisableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, renderState->mario_texture); glMatrixMode(GL_TEXTURE); glLoadIdentity(); From 43db1fb637a6c09a3c822619ee69a3539cb0d257 Mon Sep 17 00:00:00 2001 From: headshot2017 Date: Wed, 25 Jan 2023 23:18:41 -0400 Subject: [PATCH 19/19] make GL 2.0 and 800x600 default OpenGL 3.3 Core is available as a define: -DGL33_CORE --- test/main.cpp | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 06852f2..ef12037 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -84,34 +84,16 @@ int main( void ) struct Renderer *renderer; - int major, minor, selection = 0; - int w = 1280, h = 800; - printf("Select OpenGL version\n1. OpenGL 3.3 Core\n2. OpenGL 2.0\n> "); - scanf("%d", &selection); - if (selection == 2) - { - printf("Launching with OpenGL 2.0\n\n"); - major = 2; minor = 0; - renderer = &gl20_renderer; - } - else - { - printf("Launching with OpenGL 3.3 Core\n\n"); - major = 3; minor = 3; - renderer = &gl33core_renderer; - } + int major, minor; +#ifdef GL33_CORE + major = 3; minor = 3; + renderer = &gl33core_renderer; +#else + major = 2; minor = 0; + renderer = &gl20_renderer; +#endif - printf("Select window resolution\n1. 1280x800\n2. 800x600\n> "); - scanf("%d", &selection); - if (selection == 2) - { - printf("Launching in 800x600\n"); - w = 800; h = 600; - } - else - printf("Launching in 1280x600\n"); - - context_init( "libsm64", w, h, major, minor ); + context_init( "libsm64", 800, 600, major, minor ); renderer->init( &renderState, texture ); struct SM64MarioInputs marioInputs;