From f2100537351f7abf7e1a586fb195d037bc2a4143 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 18 Mar 2019 18:34:20 -0300 Subject: [PATCH] md3-vanilla --- src/CMakeLists.txt | 8 + src/Makefile | 28 +- src/doomtype.h | 16 +- src/hardware/hw_defs.h | 25 +- src/hardware/hw_drv.h | 6 +- src/hardware/hw_md2.c | 429 ++--------- src/hardware/hw_md2.h | 94 +-- src/hardware/hw_md2load.c | 564 ++++++++++++++ src/hardware/hw_md2load.h | 20 + src/hardware/hw_md3load.c | 510 +++++++++++++ src/hardware/hw_md3load.h | 19 + src/hardware/hw_model.c | 593 +++++++++++++++ src/hardware/hw_model.h | 104 +++ src/hardware/r_opengl/r_opengl.c | 994 +++++++++++++++---------- src/hardware/r_opengl/r_vbo.h | 52 ++ src/hardware/u_list.c | 231 ++++++ src/hardware/u_list.h | 29 + src/m_fixed.c | 38 +- src/m_fixed.h | 4 +- src/sdl/Srb2SDL-vc10.vcxproj | 10 +- src/sdl/Srb2SDL-vc10.vcxproj.filters | 26 +- src/sdl/hwsym_sdl.c | 3 +- src/sdl/i_video.c | 3 +- src/win32/Srb2win-vc10.vcxproj | 21 +- src/win32/Srb2win-vc10.vcxproj.filters | 56 +- 25 files changed, 2921 insertions(+), 962 deletions(-) create mode 100644 src/hardware/hw_md2load.c create mode 100644 src/hardware/hw_md2load.h create mode 100644 src/hardware/hw_md3load.c create mode 100644 src/hardware/hw_md3load.h create mode 100644 src/hardware/hw_model.c create mode 100644 src/hardware/hw_model.h create mode 100644 src/hardware/r_opengl/r_vbo.h create mode 100644 src/hardware/u_list.c create mode 100644 src/hardware/u_list.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a6fab34f..85cda35f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -399,7 +399,11 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c ) set (SRB2_HWRENDER_HEADERS @@ -413,6 +417,10 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.h + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.h + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.h + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.h ) set(SRB2_R_OPENGL_SOURCES diff --git a/src/Makefile b/src/Makefile index 6363ab7d..6f792707 100644 --- a/src/Makefile +++ b/src/Makefile @@ -279,7 +279,8 @@ ifndef DC endif OPTS+=-DHWRENDER OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ - $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o + $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o \ + $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o endif ifdef NOHS @@ -732,16 +733,18 @@ ifdef MINGW $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ - d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ + hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ + hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ + am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ else $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ - d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ + hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ + hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ + am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h $(CC) $(CFLAGS) $(WFLAGS) -I/usr/X11R6/include -c $< -o $@ endif @@ -893,24 +896,27 @@ ifndef NOHW $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ - d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ + hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ + hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ + am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ - d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ + hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ + hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ + am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(OBJDIR)/r_minigl.o: hardware/r_minigl/r_minigl.c hardware/r_opengl/r_opengl.h \ doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ command.h hardware/hw_data.h hardware/hw_glide.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h am_map.h \ - d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ + hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ + hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ + am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ endif diff --git a/src/doomtype.h b/src/doomtype.h index b44e32e4..dd4268cd 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -366,16 +366,18 @@ size_t strlcpy(char *dst, const char *src, size_t siz); /* Miscellaneous types that don't fit anywhere else (Can this be changed?) */ +typedef struct +{ + UINT8 red; + UINT8 green; + UINT8 blue; + UINT8 alpha; +} byteColor_t; + union FColorRGBA { UINT32 rgba; - struct - { - UINT8 red; - UINT8 green; - UINT8 blue; - UINT8 alpha; - } s; + byteColor_t s; } ATTRPACK; typedef union FColorRGBA RGBA_t; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b0ac599e..4fd2fd18 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -89,14 +89,29 @@ typedef struct //Hurdler: Transform (coords + angles) //BP: transform order : scale(rotation_x(rotation_y(translation(v)))) + +// Kart features +//#define USE_FTRANSFORM_ANGLEZ +//#define USE_FTRANSFORM_MIRROR + +// Vanilla features +#define USE_MODEL_NEXTFRAME + typedef struct { FLOAT x,y,z; // position +#ifdef USE_FTRANSFORM_ANGLEZ + FLOAT anglex,angley,anglez; // aimingangle / viewangle +#else FLOAT anglex,angley; // aimingangle / viewangle +#endif FLOAT scalex,scaley,scalez; FLOAT fovxangle, fovyangle; - INT32 splitscreen; + UINT8 splitscreen; boolean flip; // screenflip +#ifdef USE_FTRANSFORM_MIRROR + boolean mirror; // SRB2Kart: Encore Mode +#endif } FTransform; // Transformed vector, as passed to HWR API @@ -108,14 +123,6 @@ typedef struct FUINT argb; // flat-shaded color } FOutVector; -// jimita -typedef struct -{ - float vx, vy, vz; - float nx, ny, nz; - float s, t; -} FOutVectorMD2; - // ========================================================================== // RENDER MODES // ========================================================================== diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index e0def221..9cefff68 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -52,7 +52,8 @@ EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development -EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, INT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface); +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface); +EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT INT32 HWRAPI(GetRenderVersion) (void); @@ -95,7 +96,8 @@ struct hwdriver_s GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; SetSpecialState pfnSetSpecialState; - DrawMD2 pfnDrawMD2; + DrawModel pfnDrawModel; + CreateModelVBOs pfnCreateModelVBOs; SetTransform pfnSetTransform; GetTextureUsed pfnGetTextureUsed; GetRenderVersion pfnGetRenderVersion; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 707c16fb..708ac4a3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -35,6 +35,9 @@ #include "../w_wad.h" #include "../z_zone.h" #include "../r_things.h" +#include "../r_draw.h" +#include "../p_tick.h" +#include "hw_model.h" #include "hw_main.h" #include "../v_video.h" @@ -67,171 +70,6 @@ #include "errno.h" #endif -#define NUMVERTEXNORMALS 162 -float avertexnormals[NUMVERTEXNORMALS][3] = { -{-0.525731f, 0.000000f, 0.850651f}, -{-0.442863f, 0.238856f, 0.864188f}, -{-0.295242f, 0.000000f, 0.955423f}, -{-0.309017f, 0.500000f, 0.809017f}, -{-0.162460f, 0.262866f, 0.951056f}, -{0.000000f, 0.000000f, 1.000000f}, -{0.000000f, 0.850651f, 0.525731f}, -{-0.147621f, 0.716567f, 0.681718f}, -{0.147621f, 0.716567f, 0.681718f}, -{0.000000f, 0.525731f, 0.850651f}, -{0.309017f, 0.500000f, 0.809017f}, -{0.525731f, 0.000000f, 0.850651f}, -{0.295242f, 0.000000f, 0.955423f}, -{0.442863f, 0.238856f, 0.864188f}, -{0.162460f, 0.262866f, 0.951056f}, -{-0.681718f, 0.147621f, 0.716567f}, -{-0.809017f, 0.309017f, 0.500000f}, -{-0.587785f, 0.425325f, 0.688191f}, -{-0.850651f, 0.525731f, 0.000000f}, -{-0.864188f, 0.442863f, 0.238856f}, -{-0.716567f, 0.681718f, 0.147621f}, -{-0.688191f, 0.587785f, 0.425325f}, -{-0.500000f, 0.809017f, 0.309017f}, -{-0.238856f, 0.864188f, 0.442863f}, -{-0.425325f, 0.688191f, 0.587785f}, -{-0.716567f, 0.681718f, -0.147621f}, -{-0.500000f, 0.809017f, -0.309017f}, -{-0.525731f, 0.850651f, 0.000000f}, -{0.000000f, 0.850651f, -0.525731f}, -{-0.238856f, 0.864188f, -0.442863f}, -{0.000000f, 0.955423f, -0.295242f}, -{-0.262866f, 0.951056f, -0.162460f}, -{0.000000f, 1.000000f, 0.000000f}, -{0.000000f, 0.955423f, 0.295242f}, -{-0.262866f, 0.951056f, 0.162460f}, -{0.238856f, 0.864188f, 0.442863f}, -{0.262866f, 0.951056f, 0.162460f}, -{0.500000f, 0.809017f, 0.309017f}, -{0.238856f, 0.864188f, -0.442863f}, -{0.262866f, 0.951056f, -0.162460f}, -{0.500000f, 0.809017f, -0.309017f}, -{0.850651f, 0.525731f, 0.000000f}, -{0.716567f, 0.681718f, 0.147621f}, -{0.716567f, 0.681718f, -0.147621f}, -{0.525731f, 0.850651f, 0.000000f}, -{0.425325f, 0.688191f, 0.587785f}, -{0.864188f, 0.442863f, 0.238856f}, -{0.688191f, 0.587785f, 0.425325f}, -{0.809017f, 0.309017f, 0.500000f}, -{0.681718f, 0.147621f, 0.716567f}, -{0.587785f, 0.425325f, 0.688191f}, -{0.955423f, 0.295242f, 0.000000f}, -{1.000000f, 0.000000f, 0.000000f}, -{0.951056f, 0.162460f, 0.262866f}, -{0.850651f, -0.525731f, 0.000000f}, -{0.955423f, -0.295242f, 0.000000f}, -{0.864188f, -0.442863f, 0.238856f}, -{0.951056f, -0.162460f, 0.262866f}, -{0.809017f, -0.309017f, 0.500000f}, -{0.681718f, -0.147621f, 0.716567f}, -{0.850651f, 0.000000f, 0.525731f}, -{0.864188f, 0.442863f, -0.238856f}, -{0.809017f, 0.309017f, -0.500000f}, -{0.951056f, 0.162460f, -0.262866f}, -{0.525731f, 0.000000f, -0.850651f}, -{0.681718f, 0.147621f, -0.716567f}, -{0.681718f, -0.147621f, -0.716567f}, -{0.850651f, 0.000000f, -0.525731f}, -{0.809017f, -0.309017f, -0.500000f}, -{0.864188f, -0.442863f, -0.238856f}, -{0.951056f, -0.162460f, -0.262866f}, -{0.147621f, 0.716567f, -0.681718f}, -{0.309017f, 0.500000f, -0.809017f}, -{0.425325f, 0.688191f, -0.587785f}, -{0.442863f, 0.238856f, -0.864188f}, -{0.587785f, 0.425325f, -0.688191f}, -{0.688191f, 0.587785f, -0.425325f}, -{-0.147621f, 0.716567f, -0.681718f}, -{-0.309017f, 0.500000f, -0.809017f}, -{0.000000f, 0.525731f, -0.850651f}, -{-0.525731f, 0.000000f, -0.850651f}, -{-0.442863f, 0.238856f, -0.864188f}, -{-0.295242f, 0.000000f, -0.955423f}, -{-0.162460f, 0.262866f, -0.951056f}, -{0.000000f, 0.000000f, -1.000000f}, -{0.295242f, 0.000000f, -0.955423f}, -{0.162460f, 0.262866f, -0.951056f}, -{-0.442863f, -0.238856f, -0.864188f}, -{-0.309017f, -0.500000f, -0.809017f}, -{-0.162460f, -0.262866f, -0.951056f}, -{0.000000f, -0.850651f, -0.525731f}, -{-0.147621f, -0.716567f, -0.681718f}, -{0.147621f, -0.716567f, -0.681718f}, -{0.000000f, -0.525731f, -0.850651f}, -{0.309017f, -0.500000f, -0.809017f}, -{0.442863f, -0.238856f, -0.864188f}, -{0.162460f, -0.262866f, -0.951056f}, -{0.238856f, -0.864188f, -0.442863f}, -{0.500000f, -0.809017f, -0.309017f}, -{0.425325f, -0.688191f, -0.587785f}, -{0.716567f, -0.681718f, -0.147621f}, -{0.688191f, -0.587785f, -0.425325f}, -{0.587785f, -0.425325f, -0.688191f}, -{0.000000f, -0.955423f, -0.295242f}, -{0.000000f, -1.000000f, 0.000000f}, -{0.262866f, -0.951056f, -0.162460f}, -{0.000000f, -0.850651f, 0.525731f}, -{0.000000f, -0.955423f, 0.295242f}, -{0.238856f, -0.864188f, 0.442863f}, -{0.262866f, -0.951056f, 0.162460f}, -{0.500000f, -0.809017f, 0.309017f}, -{0.716567f, -0.681718f, 0.147621f}, -{0.525731f, -0.850651f, 0.000000f}, -{-0.238856f, -0.864188f, -0.442863f}, -{-0.500000f, -0.809017f, -0.309017f}, -{-0.262866f, -0.951056f, -0.162460f}, -{-0.850651f, -0.525731f, 0.000000f}, -{-0.716567f, -0.681718f, -0.147621f}, -{-0.716567f, -0.681718f, 0.147621f}, -{-0.525731f, -0.850651f, 0.000000f}, -{-0.500000f, -0.809017f, 0.309017f}, -{-0.238856f, -0.864188f, 0.442863f}, -{-0.262866f, -0.951056f, 0.162460f}, -{-0.864188f, -0.442863f, 0.238856f}, -{-0.809017f, -0.309017f, 0.500000f}, -{-0.688191f, -0.587785f, 0.425325f}, -{-0.681718f, -0.147621f, 0.716567f}, -{-0.442863f, -0.238856f, 0.864188f}, -{-0.587785f, -0.425325f, 0.688191f}, -{-0.309017f, -0.500000f, 0.809017f}, -{-0.147621f, -0.716567f, 0.681718f}, -{-0.425325f, -0.688191f, 0.587785f}, -{-0.162460f, -0.262866f, 0.951056f}, -{0.442863f, -0.238856f, 0.864188f}, -{0.162460f, -0.262866f, 0.951056f}, -{0.309017f, -0.500000f, 0.809017f}, -{0.147621f, -0.716567f, 0.681718f}, -{0.000000f, -0.525731f, 0.850651f}, -{0.425325f, -0.688191f, 0.587785f}, -{0.587785f, -0.425325f, 0.688191f}, -{0.688191f, -0.587785f, 0.425325f}, -{-0.955423f, 0.295242f, 0.000000f}, -{-0.951056f, 0.162460f, 0.262866f}, -{-1.000000f, 0.000000f, 0.000000f}, -{-0.850651f, 0.000000f, 0.525731f}, -{-0.955423f, -0.295242f, 0.000000f}, -{-0.951056f, -0.162460f, 0.262866f}, -{-0.864188f, 0.442863f, -0.238856f}, -{-0.951056f, 0.162460f, -0.262866f}, -{-0.809017f, 0.309017f, -0.500000f}, -{-0.864188f, -0.442863f, -0.238856f}, -{-0.951056f, -0.162460f, -0.262866f}, -{-0.809017f, -0.309017f, -0.500000f}, -{-0.681718f, 0.147621f, -0.716567f}, -{-0.681718f, -0.147621f, -0.716567f}, -{-0.850651f, 0.000000f, -0.525731f}, -{-0.688191f, 0.587785f, -0.425325f}, -{-0.587785f, 0.425325f, -0.688191f}, -{-0.425325f, 0.688191f, -0.587785f}, -{-0.425325f, -0.688191f, -0.587785f}, -{-0.587785f, -0.425325f, -0.688191f}, -{-0.688191f, -0.587785f, -0.425325f}, -}; md2_t md2_models[NUMSPRITES]; md2_t md2_playermodels[MAXSKINS]; @@ -240,194 +78,24 @@ md2_t md2_playermodels[MAXSKINS]; /* * free model */ -static void md2_freeModel (md2_model_t *model) +#if 0 +static void md2_freeModel (model_t *model) { - if (model) - { - if (model->skins) - free(model->skins); - - if (model->texCoords) - free(model->texCoords); - - if (model->triangles) - free(model->triangles); - - if (model->frames) - { - size_t i; - - for (i = 0; i < model->header.numFrames; i++) - { - if (model->frames[i].vertices) - free(model->frames[i].vertices); - } - free(model->frames); - } - - if (model->glCommandBuffer) - free(model->glCommandBuffer); - - free(model); - } + UnloadModel(model); } - +#endif // // load model // // Hurdler: the current path is the Legacy.exe path -static md2_model_t *md2_readModel(const char *filename) +static model_t *md2_readModel(const char *filename) { - FILE *file; - md2_model_t *model; - UINT8 buffer[MD2_MAX_FRAMESIZE]; - size_t i; - - model = calloc(1, sizeof (*model)); - if (model == NULL) - return 0; - //Filename checking fixed ~Monster Iestyn and Golden - file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb"); - if (!file) - { - free(model); - return 0; - } - - // initialize model and read header - - if (fread(&model->header, sizeof (model->header), 1, file) != 1 - || model->header.magic != MD2_IDENT - || model->header.version != MD2_VERSION) - { - fclose(file); - free(model); - return 0; - } - - model->header.numSkins = 1; - -#define MD2LIMITCHECK(field, max, msgname) \ - if (field > max) \ - { \ - CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \ - md2_freeModel (model); \ - fclose(file); \ - return 0; \ - } - - // Uncomment if these are actually needed -// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins") -// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates") - MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles") - MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames") - MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices") - -#undef MD2LIMITCHECK - - // read skins - fseek(file, model->header.offsetSkins, SEEK_SET); - if (model->header.numSkins > 0) - { - model->skins = calloc(sizeof (md2_skin_t), model->header.numSkins); - if (!model->skins || model->header.numSkins != - fread(model->skins, sizeof (md2_skin_t), model->header.numSkins, file)) - { - md2_freeModel (model); - fclose(file); - return 0; - } - } - - // read texture coordinates - fseek(file, model->header.offsetTexCoords, SEEK_SET); - if (model->header.numTexCoords > 0) - { - model->texCoords = calloc(sizeof (md2_textureCoordinate_t), model->header.numTexCoords); - if (!model->texCoords || model->header.numTexCoords != - fread(model->texCoords, sizeof (md2_textureCoordinate_t), model->header.numTexCoords, file)) - { - md2_freeModel (model); - fclose(file); - return 0; - } - } - - // read triangles - fseek(file, model->header.offsetTriangles, SEEK_SET); - if (model->header.numTriangles > 0) - { - model->triangles = calloc(sizeof (md2_triangle_t), model->header.numTriangles); - if (!model->triangles || model->header.numTriangles != - fread(model->triangles, sizeof (md2_triangle_t), model->header.numTriangles, file)) - { - md2_freeModel (model); - fclose(file); - return 0; - } - } - - // read alias frames - fseek(file, model->header.offsetFrames, SEEK_SET); - if (model->header.numFrames > 0) - { - model->frames = calloc(sizeof (md2_frame_t), model->header.numFrames); - if (!model->frames) - { - md2_freeModel (model); - fclose(file); - return 0; - } - - for (i = 0; i < model->header.numFrames; i++) - { - md2_alias_frame_t *frame = (md2_alias_frame_t *)(void *)buffer; - size_t j; - - model->frames[i].vertices = calloc(sizeof (md2_triangleVertex_t), model->header.numVertices); - if (!model->frames[i].vertices || model->header.frameSize != - fread(frame, 1, model->header.frameSize, file)) - { - md2_freeModel (model); - fclose(file); - return 0; - } - - strcpy(model->frames[i].name, frame->name); - for (j = 0; j < model->header.numVertices; j++) - { - model->frames[i].vertices[j].vertex[0] = (float) ((INT32) frame->alias_vertices[j].vertex[0]) * frame->scale[0] + frame->translate[0]; - model->frames[i].vertices[j].vertex[2] = -1* ((float) ((INT32) frame->alias_vertices[j].vertex[1]) * frame->scale[1] + frame->translate[1]); - model->frames[i].vertices[j].vertex[1] = (float) ((INT32) frame->alias_vertices[j].vertex[2]) * frame->scale[2] + frame->translate[2]; - model->frames[i].vertices[j].normal[0] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][0]; - model->frames[i].vertices[j].normal[1] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][1]; - model->frames[i].vertices[j].normal[2] = avertexnormals[frame->alias_vertices[j].lightNormalIndex][2]; - } - } - } - - // read gl commands - fseek(file, model->header.offsetGlCommands, SEEK_SET); - if (model->header.numGlCommands) - { - model->glCommandBuffer = calloc(sizeof (INT32), model->header.numGlCommands); - if (!model->glCommandBuffer || model->header.numGlCommands != - fread(model->glCommandBuffer, sizeof (INT32), model->header.numGlCommands, file)) - { - md2_freeModel (model); - fclose(file); - return 0; - } - } - - fclose(file); - - return model; + return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC); } -static inline void md2_printModelInfo (md2_model_t *model) +static inline void md2_printModelInfo (model_t *model) { #if 0 INT32 i; @@ -882,7 +550,7 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup return; } - // Check for any MD2s that match the names of player skins! + // Check for any MD2s that match the names of sprite names! while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) { if (stricmp(name, skins[skin].name) == 0) @@ -1195,30 +863,21 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, con // : (monsters, bonuses, weapons, lights, ...) // Returns : // -----------------+ - /* - wait/stand - death - pain - walk - shoot/fire - die? - atka? - atkb? - attacka/b/c/d? - res? - run? - */ +// hw_main.c #define NORMALFOG 0x00000000 #define FADEFOG 0x19000000 + void HWR_DrawMD2(gr_vissprite_t *spr) { - FSurfaceInfo Surf; + md2_t *md2; char filename[64]; - INT32 frame; + INT32 frame = 0; + INT32 nextFrame = -1; + FTransform p; - md2_t *md2; + FSurfaceInfo Surf; if (!cv_grmd2.value) return; @@ -1263,10 +922,9 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // Look at HWR_ProjectSprite for more { GLPatch_t *gpatch; - INT32 *buff; INT32 durs = spr->mobj->state->tics; INT32 tics = spr->mobj->tics; - md2_frame_t *curr, *next = NULL; + //mdlframe_t *next = NULL; const UINT8 flip = (UINT8)((spr->mobj->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP); spritedef_t *sprdef; spriteframe_t *sprframe; @@ -1307,6 +965,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (md2->model) { md2_printModelInfo(md2->model); + HWD.pfnCreateModelVBOs(md2->model); } else { @@ -1355,30 +1014,30 @@ void HWR_DrawMD2(gr_vissprite_t *spr) } //FIXME: this is not yet correct - frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; - buff = md2->model->glCommandBuffer; - curr = &md2->model->frames[frame]; + frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->meshes[0].numFrames; +#ifdef USE_MODEL_NEXTFRAME if (cv_grmd2.value == 1 && tics <= durs) { // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation if (spr->mobj->frame & FF_ANIMATE) { - UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; - if (nextframe >= (UINT32)spr->mobj->state->var1) - nextframe = (spr->mobj->state->frame & FF_FRAMEMASK); - nextframe %= md2->model->header.numFrames; - next = &md2->model->frames[nextframe]; + nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1; + if (nextFrame >= spr->mobj->state->var1) + nextFrame = (spr->mobj->state->frame & FF_FRAMEMASK); + nextFrame %= md2->model->meshes[0].numFrames; + //next = &md2->model->meshes[0].frames[nextFrame]; } else { if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL && !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_TAP1 || spr->mobj->state->nextstate == S_PLAY_TAP2) && spr->mobj->state == &states[S_PLAY_STND])) { - const UINT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames; - next = &md2->model->frames[nextframe]; + nextFrame = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->meshes[0].numFrames; + //next = &md2->model->meshes[0].frames[nextFrame]; } } } +#endif //Hurdler: it seems there is still a small problem with mobj angle p.x = FIXED_TO_FLOAT(spr->mobj->x); @@ -1398,7 +1057,14 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (sprframe->rotate) { - const fixed_t anglef = AngleFixed(spr->mobj->angle); + fixed_t anglef = AngleFixed(spr->mobj->angle); + // \todo adapt for 2.2 directionchar? The below code is from Kart +#if 0 + if (spr->mobj->player) + anglef = AngleFixed(spr->mobj->player->frameangle); + else + anglef = AngleFixed(spr->mobj->angle); +#endif p.angley = FIXED_TO_FLOAT(anglef); } else @@ -1407,13 +1073,30 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.angley = FIXED_TO_FLOAT(anglef); } p.anglex = 0.0f; +#ifdef USE_FTRANSFORM_ANGLEZ + // Slope rotation from Kart + p.anglez = 0.0f; + if (spr->mobj->standingslope) + { + fixed_t tempz = spr->mobj->standingslope->normal.z; + fixed_t tempy = spr->mobj->standingslope->normal.y; + fixed_t tempx = spr->mobj->standingslope->normal.x; + fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); + p.anglez = FIXED_TO_FLOAT(tempangle); + tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); + p.anglex = FIXED_TO_FLOAT(tempangle); + } +#endif // SRB2CBTODO: MD2 scaling support finalscale *= FIXED_TO_FLOAT(spr->mobj->scale); p.flip = atransform.flip; +#ifdef USE_FTRANSFORM_MIRROR + p.mirror = atransform.mirror; // from Kart +#endif - HWD.pfnDrawMD2(buff, curr, durs, tics, next, &p, finalscale, flip, &Surf); + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, &Surf); } } diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 07088643..fab8e6ad 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -16,97 +16,7 @@ #define _HW_MD2_H_ #include "hw_glob.h" - -// magic number "IDP2" or 844121161 -#define MD2_IDENT (INT32)(('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') -// model version -#define MD2_VERSION 8 - -#define MD2_MAX_TRIANGLES 8192 -#define MD2_MAX_VERTICES 4096 -#define MD2_MAX_TEXCOORDS 4096 -#define MD2_MAX_FRAMES 512 -#define MD2_MAX_SKINS 32 -#define MD2_MAX_FRAMESIZE (MD2_MAX_VERTICES * 4 + 128) - -#if defined(_MSC_VER) -#pragma pack(1) -#endif -typedef struct -{ - UINT32 magic; - UINT32 version; - UINT32 skinWidth; - UINT32 skinHeight; - UINT32 frameSize; - UINT32 numSkins; - UINT32 numVertices; - UINT32 numTexCoords; - UINT32 numTriangles; - UINT32 numGlCommands; - UINT32 numFrames; - UINT32 offsetSkins; - UINT32 offsetTexCoords; - UINT32 offsetTriangles; - UINT32 offsetFrames; - UINT32 offsetGlCommands; - UINT32 offsetEnd; -} ATTRPACK md2_header_t; //NOTE: each of md2_header's members are 4 unsigned bytes - -typedef struct -{ - UINT8 vertex[3]; - UINT8 lightNormalIndex; -} ATTRPACK md2_alias_triangleVertex_t; - -typedef struct -{ - float vertex[3]; - float normal[3]; -} ATTRPACK md2_triangleVertex_t; - -typedef struct -{ - INT16 vertexIndices[3]; - INT16 textureIndices[3]; -} ATTRPACK md2_triangle_t; - -typedef struct -{ - INT16 s, t; -} ATTRPACK md2_textureCoordinate_t; - -typedef struct -{ - float scale[3]; - float translate[3]; - char name[16]; - md2_alias_triangleVertex_t alias_vertices[1]; -} ATTRPACK md2_alias_frame_t; - -typedef struct -{ - char name[16]; - md2_triangleVertex_t *vertices; -} ATTRPACK md2_frame_t; - -typedef char md2_skin_t[64]; - -typedef struct -{ - float s, t; - INT32 vertexIndex; -} ATTRPACK md2_glCommandVertex_t; - -typedef struct -{ - md2_header_t header; - md2_skin_t *skins; - md2_textureCoordinate_t *texCoords; - md2_triangle_t *triangles; - md2_frame_t *frames; - INT32 *glCommandBuffer; -} ATTRPACK md2_model_t; +#include "hw_model.h" #if defined(_MSC_VER) #pragma pack() @@ -117,7 +27,7 @@ typedef struct char filename[32]; float scale; float offset; - md2_model_t *model; + model_t *model; void *grpatch; void *blendgrpatch; boolean notfound; diff --git a/src/hardware/hw_md2load.c b/src/hardware/hw_md2load.c new file mode 100644 index 00000000..3805deff --- /dev/null +++ b/src/hardware/hw_md2load.c @@ -0,0 +1,564 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#include +#include +#include +#include "../doomdef.h" +#include "hw_md2load.h" +#include "hw_model.h" +#include "../z_zone.h" + +#define NUMVERTEXNORMALS 162 + +// Quake 2 normals are indexed. Use avertexnormals[normalindex][x/y/z] and +// you'll have your normals. +float avertexnormals[NUMVERTEXNORMALS][3] = { +{-0.525731f, 0.000000f, 0.850651f}, +{-0.442863f, 0.238856f, 0.864188f}, +{-0.295242f, 0.000000f, 0.955423f}, +{-0.309017f, 0.500000f, 0.809017f}, +{-0.162460f, 0.262866f, 0.951056f}, +{0.000000f, 0.000000f, 1.000000f}, +{0.000000f, 0.850651f, 0.525731f}, +{-0.147621f, 0.716567f, 0.681718f}, +{0.147621f, 0.716567f, 0.681718f}, +{0.000000f, 0.525731f, 0.850651f}, +{0.309017f, 0.500000f, 0.809017f}, +{0.525731f, 0.000000f, 0.850651f}, +{0.295242f, 0.000000f, 0.955423f}, +{0.442863f, 0.238856f, 0.864188f}, +{0.162460f, 0.262866f, 0.951056f}, +{-0.681718f, 0.147621f, 0.716567f}, +{-0.809017f, 0.309017f, 0.500000f}, +{-0.587785f, 0.425325f, 0.688191f}, +{-0.850651f, 0.525731f, 0.000000f}, +{-0.864188f, 0.442863f, 0.238856f}, +{-0.716567f, 0.681718f, 0.147621f}, +{-0.688191f, 0.587785f, 0.425325f}, +{-0.500000f, 0.809017f, 0.309017f}, +{-0.238856f, 0.864188f, 0.442863f}, +{-0.425325f, 0.688191f, 0.587785f}, +{-0.716567f, 0.681718f, -0.147621f}, +{-0.500000f, 0.809017f, -0.309017f}, +{-0.525731f, 0.850651f, 0.000000f}, +{0.000000f, 0.850651f, -0.525731f}, +{-0.238856f, 0.864188f, -0.442863f}, +{0.000000f, 0.955423f, -0.295242f}, +{-0.262866f, 0.951056f, -0.162460f}, +{0.000000f, 1.000000f, 0.000000f}, +{0.000000f, 0.955423f, 0.295242f}, +{-0.262866f, 0.951056f, 0.162460f}, +{0.238856f, 0.864188f, 0.442863f}, +{0.262866f, 0.951056f, 0.162460f}, +{0.500000f, 0.809017f, 0.309017f}, +{0.238856f, 0.864188f, -0.442863f}, +{0.262866f, 0.951056f, -0.162460f}, +{0.500000f, 0.809017f, -0.309017f}, +{0.850651f, 0.525731f, 0.000000f}, +{0.716567f, 0.681718f, 0.147621f}, +{0.716567f, 0.681718f, -0.147621f}, +{0.525731f, 0.850651f, 0.000000f}, +{0.425325f, 0.688191f, 0.587785f}, +{0.864188f, 0.442863f, 0.238856f}, +{0.688191f, 0.587785f, 0.425325f}, +{0.809017f, 0.309017f, 0.500000f}, +{0.681718f, 0.147621f, 0.716567f}, +{0.587785f, 0.425325f, 0.688191f}, +{0.955423f, 0.295242f, 0.000000f}, +{1.000000f, 0.000000f, 0.000000f}, +{0.951056f, 0.162460f, 0.262866f}, +{0.850651f, -0.525731f, 0.000000f}, +{0.955423f, -0.295242f, 0.000000f}, +{0.864188f, -0.442863f, 0.238856f}, +{0.951056f, -0.162460f, 0.262866f}, +{0.809017f, -0.309017f, 0.500000f}, +{0.681718f, -0.147621f, 0.716567f}, +{0.850651f, 0.000000f, 0.525731f}, +{0.864188f, 0.442863f, -0.238856f}, +{0.809017f, 0.309017f, -0.500000f}, +{0.951056f, 0.162460f, -0.262866f}, +{0.525731f, 0.000000f, -0.850651f}, +{0.681718f, 0.147621f, -0.716567f}, +{0.681718f, -0.147621f, -0.716567f}, +{0.850651f, 0.000000f, -0.525731f}, +{0.809017f, -0.309017f, -0.500000f}, +{0.864188f, -0.442863f, -0.238856f}, +{0.951056f, -0.162460f, -0.262866f}, +{0.147621f, 0.716567f, -0.681718f}, +{0.309017f, 0.500000f, -0.809017f}, +{0.425325f, 0.688191f, -0.587785f}, +{0.442863f, 0.238856f, -0.864188f}, +{0.587785f, 0.425325f, -0.688191f}, +{0.688191f, 0.587785f, -0.425325f}, +{-0.147621f, 0.716567f, -0.681718f}, +{-0.309017f, 0.500000f, -0.809017f}, +{0.000000f, 0.525731f, -0.850651f}, +{-0.525731f, 0.000000f, -0.850651f}, +{-0.442863f, 0.238856f, -0.864188f}, +{-0.295242f, 0.000000f, -0.955423f}, +{-0.162460f, 0.262866f, -0.951056f}, +{0.000000f, 0.000000f, -1.000000f}, +{0.295242f, 0.000000f, -0.955423f}, +{0.162460f, 0.262866f, -0.951056f}, +{-0.442863f, -0.238856f, -0.864188f}, +{-0.309017f, -0.500000f, -0.809017f}, +{-0.162460f, -0.262866f, -0.951056f}, +{0.000000f, -0.850651f, -0.525731f}, +{-0.147621f, -0.716567f, -0.681718f}, +{0.147621f, -0.716567f, -0.681718f}, +{0.000000f, -0.525731f, -0.850651f}, +{0.309017f, -0.500000f, -0.809017f}, +{0.442863f, -0.238856f, -0.864188f}, +{0.162460f, -0.262866f, -0.951056f}, +{0.238856f, -0.864188f, -0.442863f}, +{0.500000f, -0.809017f, -0.309017f}, +{0.425325f, -0.688191f, -0.587785f}, +{0.716567f, -0.681718f, -0.147621f}, +{0.688191f, -0.587785f, -0.425325f}, +{0.587785f, -0.425325f, -0.688191f}, +{0.000000f, -0.955423f, -0.295242f}, +{0.000000f, -1.000000f, 0.000000f}, +{0.262866f, -0.951056f, -0.162460f}, +{0.000000f, -0.850651f, 0.525731f}, +{0.000000f, -0.955423f, 0.295242f}, +{0.238856f, -0.864188f, 0.442863f}, +{0.262866f, -0.951056f, 0.162460f}, +{0.500000f, -0.809017f, 0.309017f}, +{0.716567f, -0.681718f, 0.147621f}, +{0.525731f, -0.850651f, 0.000000f}, +{-0.238856f, -0.864188f, -0.442863f}, +{-0.500000f, -0.809017f, -0.309017f}, +{-0.262866f, -0.951056f, -0.162460f}, +{-0.850651f, -0.525731f, 0.000000f}, +{-0.716567f, -0.681718f, -0.147621f}, +{-0.716567f, -0.681718f, 0.147621f}, +{-0.525731f, -0.850651f, 0.000000f}, +{-0.500000f, -0.809017f, 0.309017f}, +{-0.238856f, -0.864188f, 0.442863f}, +{-0.262866f, -0.951056f, 0.162460f}, +{-0.864188f, -0.442863f, 0.238856f}, +{-0.809017f, -0.309017f, 0.500000f}, +{-0.688191f, -0.587785f, 0.425325f}, +{-0.681718f, -0.147621f, 0.716567f}, +{-0.442863f, -0.238856f, 0.864188f}, +{-0.587785f, -0.425325f, 0.688191f}, +{-0.309017f, -0.500000f, 0.809017f}, +{-0.147621f, -0.716567f, 0.681718f}, +{-0.425325f, -0.688191f, 0.587785f}, +{-0.162460f, -0.262866f, 0.951056f}, +{0.442863f, -0.238856f, 0.864188f}, +{0.162460f, -0.262866f, 0.951056f}, +{0.309017f, -0.500000f, 0.809017f}, +{0.147621f, -0.716567f, 0.681718f}, +{0.000000f, -0.525731f, 0.850651f}, +{0.425325f, -0.688191f, 0.587785f}, +{0.587785f, -0.425325f, 0.688191f}, +{0.688191f, -0.587785f, 0.425325f}, +{-0.955423f, 0.295242f, 0.000000f}, +{-0.951056f, 0.162460f, 0.262866f}, +{-1.000000f, 0.000000f, 0.000000f}, +{-0.850651f, 0.000000f, 0.525731f}, +{-0.955423f, -0.295242f, 0.000000f}, +{-0.951056f, -0.162460f, 0.262866f}, +{-0.864188f, 0.442863f, -0.238856f}, +{-0.951056f, 0.162460f, -0.262866f}, +{-0.809017f, 0.309017f, -0.500000f}, +{-0.864188f, -0.442863f, -0.238856f}, +{-0.951056f, -0.162460f, -0.262866f}, +{-0.809017f, -0.309017f, -0.500000f}, +{-0.681718f, 0.147621f, -0.716567f}, +{-0.681718f, -0.147621f, -0.716567f}, +{-0.850651f, 0.000000f, -0.525731f}, +{-0.688191f, 0.587785f, -0.425325f}, +{-0.587785f, 0.425325f, -0.688191f}, +{-0.425325f, 0.688191f, -0.587785f}, +{-0.425325f, -0.688191f, -0.587785f}, +{-0.587785f, -0.425325f, -0.688191f}, +{-0.688191f, -0.587785f, -0.425325f}, +}; + +typedef struct +{ + int ident; // A "magic number" that's used to identify the .md2 file + int version; // The version of the file, always 8 + int skinwidth; // Width of the skin(s) in pixels + int skinheight; // Height of the skin(s) in pixels + int framesize; // Size of each frame in bytes + int numSkins; // Number of skins with the model + int numXYZ; // Number of vertices in each frame + int numST; // Number of texture coordinates in each frame. + int numTris; // Number of triangles in each frame + int numGLcmds; // Number of dwords (4 bytes) in the gl command list. + int numFrames; // Number of frames + int offsetSkins; // Offset, in bytes from the start of the file, to the list of skin names. + int offsetST; // Offset, in bytes from the start of the file, to the list of texture coordinates + int offsetTris; // Offset, in bytes from the start of the file, to the list of triangles + int offsetFrames; // Offset, in bytes from the start of the file, to the list of frames + int offsetGLcmds; // Offset, in bytes from the start of the file, to the list of gl commands + int offsetEnd; // Offset, in bytes from the start of the file, to the end of the file (filesize) +} md2header_t; + +typedef struct +{ + unsigned short meshIndex[3]; // indices into the array of vertices in each frames + unsigned short stIndex[3]; // indices into the array of texture coordinates +} md2triangle_t; + +typedef struct +{ + short s; + short t; +} md2texcoord_t; + +typedef struct +{ + unsigned char v[3]; // Scaled vertices. You'll need to multiply them with scale[x] to make them normal. + unsigned char lightNormalIndex; // Index to the array of normals +} md2vertex_t; + +typedef struct +{ + float scale[3]; // Used by the v member in the md2framePoint structure + float translate[3]; // Used by the v member in the md2framePoint structure + char name[16]; // Name of the frame +} md2frame_t; + +// Load the model +model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat) +{ + FILE *f; + + model_t *retModel = NULL; + md2header_t *header; + + size_t fileLen; + int i, j; + size_t namelen; + char *texturefilename; + const char *texPos; + + char *buffer; + + const float WUNITS = 1.0f; + float dataScale = WUNITS; + + md2triangle_t *tris; + md2texcoord_t *texcoords; + md2frame_t *frames; + + int t; + + // MD2 currently does not work with tinyframes, so force useFloat = true + // + // + // the UV coordinates in MD2 are not compatible with glDrawElements like MD3 is. So they need to be loaded as full float. + // + // MD2 is intended to be draw in triangle strips and fans + // not very compatible with a modern GL implementation, either + // so the idea would be to full float expand it, and put it in a vertex buffer object + // I'm sure there's a way to convert the UVs to 'tinyframes', but maybe that's a job for someone else. + // You'd have to decompress the model, then recompress, reindexing the triangles and weeding out duplicate coordinates + // I already have the decompression work done + + useFloat = true; + + f = fopen(fileName, "rb"); + + if (!f) + return NULL; + + retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0); + + //size_t fileLen; + + //int i, j; + + //size_t namelen; + //char *texturefilename; + texPos = strchr(fileName, '/'); + + if (texPos) + { + texPos++; + namelen = strlen(texPos) + 1; + texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0); + strcpy(texturefilename, texPos); + } + else + { + namelen = strlen(fileName) + 1; + texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0); + strcpy(texturefilename, fileName); + } + + texturefilename[namelen - 2] = 'z'; + texturefilename[namelen - 3] = 'u'; + texturefilename[namelen - 4] = 'b'; + + // find length of file + fseek(f, 0, SEEK_END); + fileLen = ftell(f); + fseek(f, 0, SEEK_SET); + + // read in file + buffer = malloc(fileLen); + if (fread(buffer, fileLen, 1, f)) { } // squash ignored fread error + fclose(f); + + // get pointer to file header + header = (md2header_t*)buffer; + + retModel->numMeshes = 1; // MD2 only has one mesh + retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t) * retModel->numMeshes, ztag, 0); + retModel->meshes[0].numFrames = header->numFrames; + // const float WUNITS = 1.0f; + // float dataScale = WUNITS; + + // Tris and ST are simple structures that can be straight-copied + tris = (md2triangle_t*)&buffer[header->offsetTris]; + texcoords = (md2texcoord_t*)&buffer[header->offsetST]; + frames = (md2frame_t*)&buffer[header->offsetFrames]; + + // Read in textures + retModel->numMaterials = header->numSkins; + + if (retModel->numMaterials <= 0) // Always at least one skin, duh + retModel->numMaterials = 1; + + retModel->materials = (material_t*)Z_Calloc(sizeof(material_t)*retModel->numMaterials, ztag, 0); + + // int t; + for (t = 0; t < retModel->numMaterials; t++) + { + retModel->materials[t].ambient[0] = 0.8f; + retModel->materials[t].ambient[1] = 0.8f; + retModel->materials[t].ambient[2] = 0.8f; + retModel->materials[t].ambient[3] = 1.0f; + retModel->materials[t].diffuse[0] = 0.8f; + retModel->materials[t].diffuse[1] = 0.8f; + retModel->materials[t].diffuse[2] = 0.8f; + retModel->materials[t].diffuse[3] = 1.0f; + retModel->materials[t].emissive[0] = 0.0f; + retModel->materials[t].emissive[1] = 0.0f; + retModel->materials[t].emissive[2] = 0.0f; + retModel->materials[t].emissive[3] = 1.0f; + retModel->materials[t].specular[0] = 0.0f; + retModel->materials[t].specular[1] = 0.0f; + retModel->materials[t].specular[2] = 0.0f; + retModel->materials[t].specular[3] = 1.0f; + retModel->materials[t].shininess = 0.0f; + retModel->materials[t].spheremap = false; + + /* retModel->materials[t].texture = Texture::ReadTexture((char*)texturefilename, ZT_TEXTURE); + + if (!systemSucks) + { + // Check for a normal map...?? + char openfilename[1024]; + char normalMapName[1024]; + strcpy(normalMapName, texturefilename); + size_t len = strlen(normalMapName); + char *ptr = &normalMapName[len]; + ptr--; // z + ptr--; // u + ptr--; // b + ptr--; // . + *ptr++ = '_'; + *ptr++ = 'n'; + *ptr++ = '.'; + *ptr++ = 'b'; + *ptr++ = 'u'; + *ptr++ = 'z'; + *ptr++ = '\0'; + + sprintf(openfilename, "%s/%s", "textures", normalMapName); + // Convert backslashes to forward slashes + for (int k = 0; k < 1024; k++) + { + if (openfilename[k] == '\0') + break; + + if (openfilename[k] == '\\') + openfilename[k] = '/'; + } + + Resource::resource_t *res = Resource::Open(openfilename); + if (res) + { + Resource::Close(res); + retModel->materials[t].lightmap = Texture::ReadTexture(normalMapName, ZT_TEXTURE); + } + }*/ + } + + retModel->meshes[0].numTriangles = header->numTris; + + if (!useFloat) // Decompress to MD3 'tinyframe' space + { + char *ptr; + + md2triangle_t *trisPtr; + unsigned short *indexptr; + float *uvptr; + + dataScale = 0.015624f; // 1 / 64.0f + retModel->meshes[0].tinyframes = (tinyframe_t*)Z_Calloc(sizeof(tinyframe_t)*header->numFrames, ztag, 0); + retModel->meshes[0].numVertices = header->numXYZ; + retModel->meshes[0].uvs = (float*)Z_Malloc(sizeof(float) * 2 * retModel->meshes[0].numVertices, ztag, 0); + + ptr = (char*)frames; + for (i = 0; i < header->numFrames; i++, ptr += header->framesize) + { + short *vertptr; + char *normptr; + // char *tanptr; + + md2vertex_t *vertex; + + md2frame_t *framePtr = (md2frame_t*)ptr; + retModel->meshes[0].tinyframes[i].vertices = (short*)Z_Malloc(sizeof(short) * 3 * header->numXYZ, ztag, 0); + retModel->meshes[0].tinyframes[i].normals = (char*)Z_Malloc(sizeof(char) * 3 * header->numXYZ, ztag, 0); + + // if (retModel->materials[0].lightmap) + // retModel->meshes[0].tinyframes[i].tangents = (char*)malloc(sizeof(char));//(char*)Z_Malloc(sizeof(char)*3*header->numVerts, ztag); + retModel->meshes[0].indices = (unsigned short*)Z_Malloc(sizeof(unsigned short) * 3 * header->numTris, ztag, 0); + + vertptr = retModel->meshes[0].tinyframes[i].vertices; + normptr = retModel->meshes[0].tinyframes[i].normals; + + // tanptr = retModel->meshes[0].tinyframes[i].tangents; + retModel->meshes[0].tinyframes[i].material = &retModel->materials[0]; + + framePtr++; // Advance to vertex list + vertex = (md2vertex_t*)framePtr; + framePtr--; + for (j = 0; j < header->numXYZ; j++, vertex++) + { + *vertptr = (short)(((vertex->v[0] * framePtr->scale[0]) + framePtr->translate[0]) / dataScale); + vertptr++; + *vertptr = (short)(((vertex->v[2] * framePtr->scale[2]) + framePtr->translate[2]) / dataScale); + vertptr++; + *vertptr = -1.0f * (short)(((vertex->v[1] * framePtr->scale[1]) + framePtr->translate[1]) / dataScale); + vertptr++; + + // Normal + *normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][0] * 127); + *normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][2] * 127); + *normptr++ = (char)(avertexnormals[vertex->lightNormalIndex][1] * 127); + } + } + + // This doesn't need to be done every frame! + trisPtr = tris; + indexptr = retModel->meshes[0].indices; + uvptr = (float*)retModel->meshes[0].uvs; + for (j = 0; j < header->numTris; j++, trisPtr++) + { + *indexptr = trisPtr->meshIndex[0]; + indexptr++; + *indexptr = trisPtr->meshIndex[1]; + indexptr++; + *indexptr = trisPtr->meshIndex[2]; + indexptr++; + + uvptr[trisPtr->meshIndex[0] * 2] = texcoords[trisPtr->stIndex[0]].s / (float)header->skinwidth; + uvptr[trisPtr->meshIndex[0] * 2 + 1] = (texcoords[trisPtr->stIndex[0]].t / (float)header->skinheight); + uvptr[trisPtr->meshIndex[1] * 2] = texcoords[trisPtr->stIndex[1]].s / (float)header->skinwidth; + uvptr[trisPtr->meshIndex[1] * 2 + 1] = (texcoords[trisPtr->stIndex[1]].t / (float)header->skinheight); + uvptr[trisPtr->meshIndex[2] * 2] = texcoords[trisPtr->stIndex[2]].s / (float)header->skinwidth; + uvptr[trisPtr->meshIndex[2] * 2 + 1] = (texcoords[trisPtr->stIndex[2]].t / (float)header->skinheight); + } + } + else // Full float loading method + { + md2triangle_t *trisPtr; + float *uvptr; + + char *ptr; + + retModel->meshes[0].numVertices = header->numTris * 3; + retModel->meshes[0].frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t)*header->numFrames, ztag, 0); + retModel->meshes[0].uvs = (float*)Z_Malloc(sizeof(float) * 2 * retModel->meshes[0].numVertices, ztag, 0); + + trisPtr = tris; + uvptr = retModel->meshes[0].uvs; + for (i = 0; i < retModel->meshes[0].numTriangles; i++, trisPtr++) + { + *uvptr++ = texcoords[trisPtr->stIndex[0]].s / (float)header->skinwidth; + *uvptr++ = (texcoords[trisPtr->stIndex[0]].t / (float)header->skinheight); + *uvptr++ = texcoords[trisPtr->stIndex[1]].s / (float)header->skinwidth; + *uvptr++ = (texcoords[trisPtr->stIndex[1]].t / (float)header->skinheight); + *uvptr++ = texcoords[trisPtr->stIndex[2]].s / (float)header->skinwidth; + *uvptr++ = (texcoords[trisPtr->stIndex[2]].t / (float)header->skinheight); + } + + ptr = (char*)frames; + for (i = 0; i < header->numFrames; i++, ptr += header->framesize) + { + float *vertptr, *normptr; + + md2vertex_t *vertex; + + md2frame_t *framePtr = (md2frame_t*)ptr; + retModel->meshes[0].frames[i].normals = (float*)Z_Malloc(sizeof(float) * 3 * header->numTris * 3, ztag, 0); + retModel->meshes[0].frames[i].vertices = (float*)Z_Malloc(sizeof(float) * 3 * header->numTris * 3, ztag, 0); + // if (retModel->materials[0].lightmap) + // retModel->meshes[0].frames[i].tangents = (float*)malloc(sizeof(float));//(float*)Z_Malloc(sizeof(float)*3*header->numTris*3, ztag); + //float *vertptr, *normptr; + normptr = (float*)retModel->meshes[0].frames[i].normals; + vertptr = (float*)retModel->meshes[0].frames[i].vertices; + trisPtr = tris; + + retModel->meshes[0].frames[i].material = &retModel->materials[0]; + + framePtr++; // Advance to vertex list + vertex = (md2vertex_t*)framePtr; + framePtr--; + for (j = 0; j < header->numTris; j++, trisPtr++) + { + *vertptr = ((vertex[trisPtr->meshIndex[0]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS; + vertptr++; + *vertptr = ((vertex[trisPtr->meshIndex[0]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS; + vertptr++; + *vertptr = -1.0f * ((vertex[trisPtr->meshIndex[0]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS; + vertptr++; + + *vertptr = ((vertex[trisPtr->meshIndex[1]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS; + vertptr++; + *vertptr = ((vertex[trisPtr->meshIndex[1]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS; + vertptr++; + *vertptr = -1.0f * ((vertex[trisPtr->meshIndex[1]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS; + vertptr++; + + *vertptr = ((vertex[trisPtr->meshIndex[2]].v[0] * framePtr->scale[0]) + framePtr->translate[0]) * WUNITS; + vertptr++; + *vertptr = ((vertex[trisPtr->meshIndex[2]].v[2] * framePtr->scale[2]) + framePtr->translate[2]) * WUNITS; + vertptr++; + *vertptr = -1.0f * ((vertex[trisPtr->meshIndex[2]].v[1] * framePtr->scale[1]) + framePtr->translate[1]) * WUNITS; + vertptr++; + + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][0]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][2]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[0]].lightNormalIndex][1]; + + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][0]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][2]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[1]].lightNormalIndex][1]; + + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][0]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][2]; + *normptr++ = avertexnormals[vertex[trisPtr->meshIndex[2]].lightNormalIndex][1]; + } + } + } + + free(buffer); + return retModel; +} diff --git a/src/hardware/hw_md2load.h b/src/hardware/hw_md2load.h new file mode 100644 index 00000000..942aac1a --- /dev/null +++ b/src/hardware/hw_md2load.h @@ -0,0 +1,20 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#ifndef _HW_MD2LOAD_H_ +#define _HW_MD2LOAD_H_ + +#include "hw_model.h" +#include "../doomtype.h" + +// Load the Model +model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat); + +#endif + diff --git a/src/hardware/hw_md3load.c b/src/hardware/hw_md3load.c new file mode 100644 index 00000000..53f6034c --- /dev/null +++ b/src/hardware/hw_md3load.c @@ -0,0 +1,510 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#include +#include +#include +#include "../doomdef.h" +#include "hw_md3load.h" +#include "hw_model.h" +#include "../z_zone.h" + +typedef struct +{ + int ident; // A "magic number" that's used to identify the .md3 file + int version; // The version of the file, always 15 + char name[64]; + int flags; + int numFrames; // Number of frames + int numTags; + int numSurfaces; + int numSkins; // Number of skins with the model + int offsetFrames; + int offsetTags; + int offsetSurfaces; + int offsetEnd; // Offset, in bytes from the start of the file, to the end of the file (filesize) +} md3modelHeader; + +typedef struct +{ + float minBounds[3]; // First corner of the bounding box + float maxBounds[3]; // Second corner of the bounding box + float localOrigin[3]; // Local origin, usually (0, 0, 0) + float radius; // Radius of bounding sphere + char name[16]; // Name of frame +} md3Frame; + +typedef struct +{ + char name[64]; // Name of tag + float origin[3]; // Coordinates of tag + float axis[9]; // Orientation of tag object +} md3Tag; + +typedef struct +{ + int ident; + char name[64]; // Name of this surface + int flags; + int numFrames; // # of keyframes + int numShaders; // # of shaders + int numVerts; // # of vertices + int numTriangles; // # of triangles + int offsetTriangles; // Relative offset from start of this struct to where the list of Triangles start + int offsetShaders; // Relative offset from start of this struct to where the list of Shaders start + int offsetST; // Relative offset from start of this struct to where the list of tex coords start + int offsetXYZNormal; // Relative offset from start of this struct to where the list of vertices start + int offsetEnd; // Relative offset from start of this struct to where this surface ends +} md3Surface; + +typedef struct +{ + char name[64]; // Name of this shader + int shaderIndex; // Shader index number +} md3Shader; + +typedef struct +{ + int index[3]; // List of offset values into the list of Vertex objects that constitute the corners of the Triangle object. +} md3Triangle; + +typedef struct +{ + float st[2]; +} md3TexCoord; + +typedef struct +{ + short x, y, z, n; +} md3Vertex; + +static float latlnglookup[256][256][3]; + +static void GetNormalFromLatLong(short latlng, float *out) +{ + float *lookup = latlnglookup[(unsigned char)(latlng >> 8)][(unsigned char)(latlng & 255)]; + + out[0] = *lookup++; + out[1] = *lookup++; + out[2] = *lookup++; +} + +#if 0 +static void NormalToLatLng(float *n, short *out) +{ + // Special cases + if (0.0f == n[0] && 0.0f == n[1]) + { + if (n[2] > 0.0f) + *out = 0; + else + *out = 128; + } + else + { + char x, y; + + x = (char)(57.2957795f * (atan2(n[1], n[0])) * (255.0f / 360.0f)); + y = (char)(57.2957795f * (acos(n[2])) * (255.0f / 360.0f)); + + *out = (x << 8) + y; + } +} +#endif + +static inline void LatLngToNormal(short n, float *out) +{ + const float PI = (3.1415926535897932384626433832795f); + float lat = (float)(n >> 8); + float lng = (float)(n & 255); + + lat *= PI / 128.0f; + lng *= PI / 128.0f; + + out[0] = cosf(lat) * sinf(lng); + out[1] = sinf(lat) * sinf(lng); + out[2] = cosf(lng); +} + +static void LatLngInit(void) +{ + int i, j; + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + LatLngToNormal((short)((i << 8) + j), latlnglookup[i][j]); + } +} + +static boolean latlnginit = false; + +model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat) +{ + const float WUNITS = 1.0f; + model_t *retModel = NULL; + md3modelHeader *mdh; + long fileLen; + long fileReadLen; + char *buffer; + int surfEnd; + int i, t; + int matCount; + FILE *f; + + if (!latlnginit) + { + LatLngInit(); + latlnginit = true; + } + + f = fopen(fileName, "rb"); + + if (!f) + return NULL; + + retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0); + + // find length of file + fseek(f, 0, SEEK_END); + fileLen = ftell(f); + fseek(f, 0, SEEK_SET); + + // read in file + buffer = malloc(fileLen); + fileReadLen = fread(buffer, fileLen, 1, f); + fclose(f); + + (void)fileReadLen; // intentionally ignore return value, per buildbot + + // get pointer to file header + mdh = (md3modelHeader*)buffer; + + retModel->numMeshes = mdh->numSurfaces; + + retModel->numMaterials = 0; + surfEnd = 0; + for (i = 0; i < mdh->numSurfaces; i++) + { + md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces]; + surfEnd += mdS->offsetEnd; + + retModel->numMaterials += mdS->numShaders; + } + + // Initialize materials + if (retModel->numMaterials <= 0) // Always at least one skin, duh + retModel->numMaterials = 1; + + retModel->materials = (material_t*)Z_Calloc(sizeof(material_t)*retModel->numMaterials, ztag, 0); + + for (t = 0; t < retModel->numMaterials; t++) + { + retModel->materials[t].ambient[0] = 0.3686f; + retModel->materials[t].ambient[1] = 0.3684f; + retModel->materials[t].ambient[2] = 0.3684f; + retModel->materials[t].ambient[3] = 1.0f; + retModel->materials[t].diffuse[0] = 0.8863f; + retModel->materials[t].diffuse[1] = 0.8850f; + retModel->materials[t].diffuse[2] = 0.8850f; + retModel->materials[t].diffuse[3] = 1.0f; + retModel->materials[t].emissive[0] = 0.0f; + retModel->materials[t].emissive[1] = 0.0f; + retModel->materials[t].emissive[2] = 0.0f; + retModel->materials[t].emissive[3] = 1.0f; + retModel->materials[t].specular[0] = 0.4902f; + retModel->materials[t].specular[1] = 0.4887f; + retModel->materials[t].specular[2] = 0.4887f; + retModel->materials[t].specular[3] = 1.0f; + retModel->materials[t].shininess = 25.0f; + retModel->materials[t].spheremap = false; + } + + retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t)*retModel->numMeshes, ztag, 0); + + matCount = 0; + for (i = 0, surfEnd = 0; i < mdh->numSurfaces; i++) + { + int j; + md3Shader *mdShader; + md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces + surfEnd]; + surfEnd += mdS->offsetEnd; + + mdShader = (md3Shader*)((char*)mdS + mdS->offsetShaders); + + for (j = 0; j < mdS->numShaders; j++, matCount++) + { + size_t len = strlen(mdShader[j].name); + mdShader[j].name[len-1] = 'z'; + mdShader[j].name[len-2] = 'u'; + mdShader[j].name[len-3] = 'b'; + + // Load material +/* retModel->materials[matCount].texture = Texture::ReadTexture(mdShader[j].name, ZT_TEXTURE); + + if (!systemSucks) + { + // Check for a normal map...?? + char openfilename[1024]; + char normalMapName[1024]; + strcpy(normalMapName, mdShader[j].name); + len = strlen(normalMapName); + char *ptr = &normalMapName[len]; + ptr--; // z + ptr--; // u + ptr--; // b + ptr--; // . + *ptr++ = '_'; + *ptr++ = 'n'; + *ptr++ = '.'; + *ptr++ = 'b'; + *ptr++ = 'u'; + *ptr++ = 'z'; + *ptr++ = '\0'; + + sprintf(openfilename, "%s/%s", "textures", normalMapName); + // Convert backslashes to forward slashes + for (int k = 0; k < 1024; k++) + { + if (openfilename[k] == '\0') + break; + + if (openfilename[k] == '\\') + openfilename[k] = '/'; + } + + Resource::resource_t *res = Resource::Open(openfilename); + if (res) + { + Resource::Close(res); + retModel->materials[matCount].lightmap = Texture::ReadTexture(normalMapName, ZT_TEXTURE); + } + }*/ + } + + retModel->meshes[i].numFrames = mdS->numFrames; + retModel->meshes[i].numTriangles = mdS->numTriangles; + + if (!useFloat) // 'tinyframe' mode with indices + { + float tempNormal[3]; + float *uvptr; + md3TexCoord *mdST; + unsigned short *indexptr; + md3Triangle *mdT; + + retModel->meshes[i].tinyframes = (tinyframe_t*)Z_Calloc(sizeof(tinyframe_t)*mdS->numFrames, ztag, 0); + retModel->meshes[i].numVertices = mdS->numVerts; + retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numVerts, ztag, 0); + for (j = 0; j < mdS->numFrames; j++) + { + short *vertptr; + char *normptr; + // char *tanptr; + int k; + md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex))); + retModel->meshes[i].tinyframes[j].vertices = (short*)Z_Malloc(sizeof(short)*3*mdS->numVerts, ztag, 0); + retModel->meshes[i].tinyframes[j].normals = (char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag, 0); + +// if (retModel->materials[0].lightmap) +// retModel->meshes[i].tinyframes[j].tangents = (char*)malloc(sizeof(char));//(char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag); + retModel->meshes[i].indices = (unsigned short*)Z_Malloc(sizeof(unsigned short) * 3 * mdS->numTriangles, ztag, 0); + vertptr = retModel->meshes[i].tinyframes[j].vertices; + normptr = retModel->meshes[i].tinyframes[j].normals; + +// tanptr = retModel->meshes[i].tinyframes[j].tangents; + retModel->meshes[i].tinyframes[j].material = &retModel->materials[i]; + + for (k = 0; k < mdS->numVerts; k++) + { + // Vertex + *vertptr = mdV[k].x; + vertptr++; + *vertptr = mdV[k].z; + vertptr++; + *vertptr = 1.0f - mdV[k].y; + vertptr++; + + // Normal + GetNormalFromLatLong(mdV[k].n, tempNormal); + *normptr = (char)(tempNormal[0] * 127); + normptr++; + *normptr = (char)(tempNormal[2] * 127); + normptr++; + *normptr = (char)(tempNormal[1] * 127); + normptr++; + } + } + + uvptr = (float*)retModel->meshes[i].uvs; + mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST); + for (j = 0; j < mdS->numVerts; j++) + { + *uvptr = mdST[j].st[0]; + uvptr++; + *uvptr = mdST[j].st[1]; + uvptr++; + } + + indexptr = retModel->meshes[i].indices; + mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles); + for (j = 0; j < mdS->numTriangles; j++, mdT++) + { + // Indices + *indexptr = (unsigned short)mdT->index[0]; + indexptr++; + *indexptr = (unsigned short)mdT->index[1]; + indexptr++; + *indexptr = (unsigned short)mdT->index[2]; + indexptr++; + } + } + else // Traditional full-float loading method + { + float dataScale = 0.015624f * WUNITS; + float tempNormal[3]; + md3TexCoord *mdST; + md3Triangle *mdT; + float *uvptr; + int k; + + retModel->meshes[i].numVertices = mdS->numTriangles * 3;//mdS->numVerts; + retModel->meshes[i].frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t)*mdS->numFrames, ztag, 0); + retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numTriangles*3, ztag, 0); + + for (j = 0; j < mdS->numFrames; j++) + { + float *vertptr; + float *normptr; + md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex))); + retModel->meshes[i].frames[j].vertices = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0); + retModel->meshes[i].frames[j].normals = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0); +// if (retModel->materials[i].lightmap) +// retModel->meshes[i].frames[j].tangents = (float*)malloc(sizeof(float));//(float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag); + vertptr = retModel->meshes[i].frames[j].vertices; + normptr = retModel->meshes[i].frames[j].normals; + retModel->meshes[i].frames[j].material = &retModel->materials[i]; + + mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles); + + for (k = 0; k < mdS->numTriangles; k++) + { + // Vertex 1 + *vertptr = mdV[mdT->index[0]].x * dataScale; + vertptr++; + *vertptr = mdV[mdT->index[0]].z * dataScale; + vertptr++; + *vertptr = 1.0f - mdV[mdT->index[0]].y * dataScale; + vertptr++; + + GetNormalFromLatLong(mdV[mdT->index[0]].n, tempNormal); + *normptr = tempNormal[0]; + normptr++; + *normptr = tempNormal[2]; + normptr++; + *normptr = tempNormal[1]; + normptr++; + + // Vertex 2 + *vertptr = mdV[mdT->index[1]].x * dataScale; + vertptr++; + *vertptr = mdV[mdT->index[1]].z * dataScale; + vertptr++; + *vertptr = 1.0f - mdV[mdT->index[1]].y * dataScale; + vertptr++; + + GetNormalFromLatLong(mdV[mdT->index[1]].n, tempNormal); + *normptr = tempNormal[0]; + normptr++; + *normptr = tempNormal[2]; + normptr++; + *normptr = tempNormal[1]; + normptr++; + + // Vertex 3 + *vertptr = mdV[mdT->index[2]].x * dataScale; + vertptr++; + *vertptr = mdV[mdT->index[2]].z * dataScale; + vertptr++; + *vertptr = 1.0f - mdV[mdT->index[2]].y * dataScale; + vertptr++; + + GetNormalFromLatLong(mdV[mdT->index[2]].n, tempNormal); + *normptr = tempNormal[0]; + normptr++; + *normptr = tempNormal[2]; + normptr++; + *normptr = tempNormal[1]; + normptr++; + + mdT++; // Advance to next triangle + } + } + + mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST); + uvptr = (float*)retModel->meshes[i].uvs; + mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles); + + for (k = 0; k < mdS->numTriangles; k++) + { + *uvptr = mdST[mdT->index[0]].st[0]; + uvptr++; + *uvptr = mdST[mdT->index[0]].st[1]; + uvptr++; + + *uvptr = mdST[mdT->index[1]].st[0]; + uvptr++; + *uvptr = mdST[mdT->index[1]].st[1]; + uvptr++; + + *uvptr = mdST[mdT->index[2]].st[0]; + uvptr++; + *uvptr = mdST[mdT->index[2]].st[1]; + uvptr++; + + mdT++; // Advance to next triangle + } + } + } + /* + // Tags? + retModel->numTags = mdh->numTags; + retModel->maxNumFrames = mdh->numFrames; + retModel->tags = (tag_t*)Z_Calloc(sizeof(tag_t) * retModel->numTags * mdh->numFrames, ztag); + md3Tag *mdTag = (md3Tag*)&buffer[mdh->offsetTags]; + tag_t *curTag = retModel->tags; + for (i = 0; i < mdh->numFrames; i++) + { + int j; + for (j = 0; j < retModel->numTags; j++, mdTag++) + { + strcpys(curTag->name, mdTag->name, sizeof(curTag->name) / sizeof(char)); + curTag->transform.m[0][0] = mdTag->axis[0]; + curTag->transform.m[0][1] = mdTag->axis[1]; + curTag->transform.m[0][2] = mdTag->axis[2]; + curTag->transform.m[1][0] = mdTag->axis[3]; + curTag->transform.m[1][1] = mdTag->axis[4]; + curTag->transform.m[1][2] = mdTag->axis[5]; + curTag->transform.m[2][0] = mdTag->axis[6]; + curTag->transform.m[2][1] = mdTag->axis[7]; + curTag->transform.m[2][2] = mdTag->axis[8]; + curTag->transform.m[3][0] = mdTag->origin[0] * WUNITS; + curTag->transform.m[3][1] = mdTag->origin[1] * WUNITS; + curTag->transform.m[3][2] = mdTag->origin[2] * WUNITS; + curTag->transform.m[3][3] = 1.0f; + + Matrix::Rotate(&curTag->transform, 90.0f, &Vector::Xaxis); + curTag++; + } + }*/ + + + free(buffer); + + return retModel; +} diff --git a/src/hardware/hw_md3load.h b/src/hardware/hw_md3load.h new file mode 100644 index 00000000..c0e0522f --- /dev/null +++ b/src/hardware/hw_md3load.h @@ -0,0 +1,19 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#ifndef _HW_MD3LOAD_H_ +#define _HW_MD3LOAD_H_ + +#include "hw_model.h" +#include "../doomtype.h" + +// Load the Model +model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat); + +#endif diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c new file mode 100644 index 00000000..2c36f974 --- /dev/null +++ b/src/hardware/hw_model.c @@ -0,0 +1,593 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#include "../z_zone.h" +#include "../doomdef.h" +#include "hw_model.h" +#include "hw_md2load.h" +#include "hw_md3load.h" +#include "u_list.h" +#include + +static float PI = (3.1415926535897932384626433832795f); +static float U_Deg2Rad(float deg) +{ + return deg * ((float)PI / 180.0f); +} + +vector_t vectorXaxis = { 1.0f, 0.0f, 0.0f }; +vector_t vectorYaxis = { 0.0f, 1.0f, 0.0f }; +vector_t vectorZaxis = { 0.0f, 0.0f, 1.0f }; + +void VectorRotate(vector_t *rotVec, const vector_t *axisVec, float angle) +{ + float ux, uy, uz, vx, vy, vz, wx, wy, wz, sa, ca; + + angle = U_Deg2Rad(angle); + + // Rotate the point (x,y,z) around the vector (u,v,w) + ux = axisVec->x * rotVec->x; + uy = axisVec->x * rotVec->y; + uz = axisVec->x * rotVec->z; + vx = axisVec->y * rotVec->x; + vy = axisVec->y * rotVec->y; + vz = axisVec->y * rotVec->z; + wx = axisVec->z * rotVec->x; + wy = axisVec->z * rotVec->y; + wz = axisVec->z * rotVec->z; + sa = sinf(angle); + ca = cosf(angle); + + rotVec->x = axisVec->x*(ux + vy + wz) + (rotVec->x*(axisVec->y*axisVec->y + axisVec->z*axisVec->z) - axisVec->x*(vy + wz))*ca + (-wy + vz)*sa; + rotVec->y = axisVec->y*(ux + vy + wz) + (rotVec->y*(axisVec->x*axisVec->x + axisVec->z*axisVec->z) - axisVec->y*(ux + wz))*ca + (wx - uz)*sa; + rotVec->z = axisVec->z*(ux + vy + wz) + (rotVec->z*(axisVec->x*axisVec->x + axisVec->y*axisVec->y) - axisVec->z*(ux + vy))*ca + (-vx + uy)*sa; +} + +void UnloadModel(model_t *model) +{ + // Wouldn't it be great if C just had destructors? + int i; + for (i = 0; i < model->numMeshes; i++) + { + mesh_t *mesh = &model->meshes[i]; + + if (mesh->frames) + { + int j; + for (j = 0; j < mesh->numFrames; j++) + { + if (mesh->frames[j].normals) + Z_Free(mesh->frames[j].normals); + + if (mesh->frames[j].tangents) + Z_Free(mesh->frames[j].tangents); + + if (mesh->frames[j].vertices) + Z_Free(mesh->frames[j].vertices); + + if (mesh->frames[j].colors) + Z_Free(mesh->frames[j].colors); + } + + Z_Free(mesh->frames); + } + else if (mesh->tinyframes) + { + int j; + for (j = 0; j < mesh->numFrames; j++) + { + if (mesh->tinyframes[j].normals) + Z_Free(mesh->tinyframes[j].normals); + + if (mesh->tinyframes[j].tangents) + Z_Free(mesh->tinyframes[j].tangents); + + if (mesh->tinyframes[j].vertices) + Z_Free(mesh->tinyframes[j].vertices); + } + + if (mesh->indices) + Z_Free(mesh->indices); + + Z_Free(mesh->tinyframes); + } + + if (mesh->uvs) + Z_Free(mesh->uvs); + + if (mesh->lightuvs) + Z_Free(mesh->lightuvs); + } + + if (model->meshes) + Z_Free(model->meshes); + + if (model->tags) + Z_Free(model->tags); + + if (model->materials) + Z_Free(model->materials); + + DeleteVBOs(model); + Z_Free(model); +} + +tag_t *GetTagByName(model_t *model, char *name, int frame) +{ + if (frame < model->maxNumFrames) + { + tag_t *iterator = &model->tags[frame * model->numTags]; + + int i; + for (i = 0; i < model->numTags; i++) + { + if (!stricmp(iterator[i].name, name)) + return &iterator[i]; + } + } + + return NULL; +} + +// +// LoadModel +// +// Load a model and +// convert it to the +// internal format. +// +model_t *LoadModel(const char *filename, int ztag) +{ + model_t *model; + + // What type of file? + const char *extension = NULL; + int i; + for (i = (int)strlen(filename)-1; i >= 0; i--) + { + if (filename[i] != '.') + continue; + + extension = &filename[i]; + break; + } + + if (!extension) + { + CONS_Printf("Model %s is lacking a file extension, unable to determine type!\n", filename); + return NULL; + } + + if (!strcmp(extension, ".md3")) + { + if (!(model = MD3_LoadModel(filename, ztag, false))) + return NULL; + } + else if (!strcmp(extension, ".md3s")) // MD3 that will be converted in memory to use full floats + { + if (!(model = MD3_LoadModel(filename, ztag, true))) + return NULL; + } + else if (!strcmp(extension, ".md2")) + { + if (!(model = MD2_LoadModel(filename, ztag, false))) + return NULL; + } + else if (!strcmp(extension, ".md2s")) + { + if (!(model = MD2_LoadModel(filename, ztag, true))) + return NULL; + } + else + { + CONS_Printf("Unknown model format: %s\n", extension); + return NULL; + } + + model->mdlFilename = (char*)Z_Malloc(strlen(filename)+1, ztag, 0); + strcpy(model->mdlFilename, filename); + + Optimize(model); + GeneratePolygonNormals(model, ztag); + + // Default material properties + for (i = 0 ; i < model->numMaterials; i++) + { + material_t *material = &model->materials[i]; + material->ambient[0] = 0.7686f; + material->ambient[1] = 0.7686f; + material->ambient[2] = 0.7686f; + material->ambient[3] = 1.0f; + material->diffuse[0] = 0.5863f; + material->diffuse[1] = 0.5863f; + material->diffuse[2] = 0.5863f; + material->diffuse[3] = 1.0f; + material->specular[0] = 0.4902f; + material->specular[1] = 0.4902f; + material->specular[2] = 0.4902f; + material->specular[3] = 1.0f; + material->shininess = 25.0f; + } + + return model; +} + +// +// GenerateVertexNormals +// +// Creates a new normal for a vertex using the average of all of the polygons it belongs to. +// +void GenerateVertexNormals(model_t *model) +{ + int i; + for (i = 0; i < model->numMeshes; i++) + { + int j; + + mesh_t *mesh = &model->meshes[i]; + + if (!mesh->frames) + continue; + + for (j = 0; j < mesh->numFrames; j++) + { + mdlframe_t *frame = &mesh->frames[j]; + int memTag = PU_STATIC; + float *newNormals = (float*)Z_Malloc(sizeof(float)*3*mesh->numTriangles*3, memTag, 0); + int k; + float *vertPtr = frame->vertices; + float *oldNormals; + + M_Memcpy(newNormals, frame->normals, sizeof(float)*3*mesh->numTriangles*3); + +/* if (!systemSucks) + { + memTag = Z_GetTag(frame->tangents); + float *newTangents = (float*)Z_Malloc(sizeof(float)*3*mesh->numTriangles*3, memTag); + M_Memcpy(newTangents, frame->tangents, sizeof(float)*3*mesh->numTriangles*3); + }*/ + + for (k = 0; k < mesh->numVertices; k++) + { + float x, y, z; + int vCount = 0; + vector_t normal; + int l; + float *testPtr = frame->vertices; + + x = *vertPtr++; + y = *vertPtr++; + z = *vertPtr++; + + normal.x = normal.y = normal.z = 0; + + for (l = 0; l < mesh->numVertices; l++) + { + float testX, testY, testZ; + testX = *testPtr++; + testY = *testPtr++; + testZ = *testPtr++; + + if (fabsf(x - testX) > FLT_EPSILON + || fabsf(y - testY) > FLT_EPSILON + || fabsf(z - testZ) > FLT_EPSILON) + continue; + + // Found a vertex match! Add it... + normal.x += frame->normals[3 * l + 0]; + normal.y += frame->normals[3 * l + 1]; + normal.z += frame->normals[3 * l + 2]; + vCount++; + } + + if (vCount > 1) + { +// Vector::Normalize(&normal); + newNormals[3 * k + 0] = (float)normal.x; + newNormals[3 * k + 1] = (float)normal.y; + newNormals[3 * k + 2] = (float)normal.z; + +/* if (!systemSucks) + { + Vector::vector_t tangent; + Vector::Tangent(&normal, &tangent); + newTangents[3 * k + 0] = tangent.x; + newTangents[3 * k + 1] = tangent.y; + newTangents[3 * k + 2] = tangent.z; + }*/ + } + } + + oldNormals = frame->normals; + frame->normals = newNormals; + Z_Free(oldNormals); + +/* if (!systemSucks) + { + float *oldTangents = frame->tangents; + frame->tangents = newTangents; + Z_Free(oldTangents); + }*/ + } + } +} + +typedef struct materiallist_s +{ + struct materiallist_s *next; + struct materiallist_s *prev; + material_t *material; +} materiallist_t; + +static boolean AddMaterialToList(materiallist_t **head, material_t *material) +{ + materiallist_t *node, *newMatNode; + for (node = *head; node; node = node->next) + { + if (node->material == material) + return false; + } + + // Didn't find it, so add to the list + newMatNode = (materiallist_t*)Z_Malloc(sizeof(materiallist_t), PU_CACHE, 0); + newMatNode->material = material; + ListAdd(newMatNode, (listitem_t**)head); + return true; +} + +// +// Optimize +// +// Groups triangles from meshes in the model +// Only works for models with 1 frame +// +void Optimize(model_t *model) +{ + int numMeshes = 0; + int i; + materiallist_t *matListHead = NULL; + int memTag; + mesh_t *newMeshes; + materiallist_t *node; + + if (model->numMeshes <= 1) + return; // No need + + for (i = 0; i < model->numMeshes; i++) + { + mesh_t *curMesh = &model->meshes[i]; + + if (curMesh->numFrames > 1) + return; // Can't optimize models with > 1 frame + + if (!curMesh->frames) + return; // Don't optimize tinyframe models (no need) + + // We are condensing to 1 mesh per material, so + // the # of materials we use will be the new + // # of meshes + if (AddMaterialToList(&matListHead, curMesh->frames[0].material)) + numMeshes++; + } + + memTag = PU_STATIC; + newMeshes = (mesh_t*)Z_Calloc(sizeof(mesh_t) * numMeshes, memTag, 0); + + i = 0; + for (node = matListHead; node; node = node->next) + { + material_t *curMat = node->material; + mesh_t *newMesh = &newMeshes[i]; + mdlframe_t *curFrame; + int uvCount; + int vertCount; + int colorCount; + + // Find all triangles with this material and count them + int numTriangles = 0; + int j; + for (j = 0; j < model->numMeshes; j++) + { + mesh_t *curMesh = &model->meshes[j]; + + if (curMesh->frames[0].material == curMat) + numTriangles += curMesh->numTriangles; + } + + newMesh->numFrames = 1; + newMesh->numTriangles = numTriangles; + newMesh->numVertices = numTriangles * 3; + newMesh->uvs = (float*)Z_Malloc(sizeof(float)*2*numTriangles*3, memTag, 0); +// if (node->material->lightmap) +// newMesh->lightuvs = (float*)Z_Malloc(sizeof(float)*2*numTriangles*3, memTag, 0); + newMesh->frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t), memTag, 0); + curFrame = &newMesh->frames[0]; + + curFrame->material = curMat; + curFrame->normals = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0); +// if (!systemSucks) +// curFrame->tangents = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0); + curFrame->vertices = (float*)Z_Malloc(sizeof(float)*3*numTriangles*3, memTag, 0); + curFrame->colors = (char*)Z_Malloc(sizeof(char)*4*numTriangles*3, memTag, 0); + + // Now traverse the meshes of the model, adding in + // vertices/normals/uvs that match the current material + uvCount = 0; + vertCount = 0; + colorCount = 0; + for (j = 0; j < model->numMeshes; j++) + { + mesh_t *curMesh = &model->meshes[j]; + + if (curMesh->frames[0].material == curMat) + { + float *dest; + float *src; + char *destByte; + char *srcByte; + + M_Memcpy(&newMesh->uvs[uvCount], + curMesh->uvs, + sizeof(float)*2*curMesh->numTriangles*3); + +/* if (node->material->lightmap) + { + M_Memcpy(&newMesh->lightuvs[uvCount], + curMesh->lightuvs, + sizeof(float)*2*curMesh->numTriangles*3); + }*/ + uvCount += 2*curMesh->numTriangles*3; + + dest = (float*)newMesh->frames[0].vertices; + src = (float*)curMesh->frames[0].vertices; + M_Memcpy(&dest[vertCount], + src, + sizeof(float)*3*curMesh->numTriangles*3); + + dest = (float*)newMesh->frames[0].normals; + src = (float*)curMesh->frames[0].normals; + M_Memcpy(&dest[vertCount], + src, + sizeof(float)*3*curMesh->numTriangles*3); + +/* if (!systemSucks) + { + dest = (float*)newMesh->frames[0].tangents; + src = (float*)curMesh->frames[0].tangents; + M_Memcpy(&dest[vertCount], + src, + sizeof(float)*3*curMesh->numTriangles*3); + }*/ + + vertCount += 3 * curMesh->numTriangles * 3; + + destByte = (char*)newMesh->frames[0].colors; + srcByte = (char*)curMesh->frames[0].colors; + + if (srcByte) + { + M_Memcpy(&destByte[colorCount], + srcByte, + sizeof(char)*4*curMesh->numTriangles*3); + } + else + { + memset(&destByte[colorCount], + 255, + sizeof(char)*4*curMesh->numTriangles*3); + } + + colorCount += 4 * curMesh->numTriangles * 3; + } + } + + i++; + } + + CONS_Printf("Model::Optimize(): Model reduced from %d to %d meshes.\n", model->numMeshes, numMeshes); + model->meshes = newMeshes; + model->numMeshes = numMeshes; +} + +void GeneratePolygonNormals(model_t *model, int ztag) +{ + int i; + for (i = 0; i < model->numMeshes; i++) + { + int j; + mesh_t *mesh = &model->meshes[i]; + + if (!mesh->frames) + continue; + + for (j = 0; j < mesh->numFrames; j++) + { + int k; + mdlframe_t *frame = &mesh->frames[j]; + const float *vertices = frame->vertices; + vector_t *polyNormals; + + frame->polyNormals = (vector_t*)Z_Malloc(sizeof(vector_t) * mesh->numTriangles, ztag, 0); + + polyNormals = frame->polyNormals; + + for (k = 0; k < mesh->numTriangles; k++) + { +// Vector::Normal(vertices, polyNormals); + vertices += 3 * 3; + polyNormals++; + } + } + } +} + +// +// Reload +// +// Reload VBOs +// +#if 0 +static void Reload(void) +{ +/* model_t *node; + for (node = modelHead; node; node = node->next) + { + int i; + for (i = 0; i < node->numMeshes; i++) + { + mesh_t *mesh = &node->meshes[i]; + + if (mesh->frames) + { + int j; + for (j = 0; j < mesh->numFrames; j++) + CreateVBO(mesh, &mesh->frames[j]); + } + else if (mesh->tinyframes) + { + int j; + for (j = 0; j < mesh->numFrames; j++) + CreateVBO(mesh, &mesh->tinyframes[j]); + } + } + }*/ +} +#endif + +void DeleteVBOs(model_t *model) +{ + (void)model; +/* for (int i = 0; i < model->numMeshes; i++) + { + mesh_t *mesh = &model->meshes[i]; + + if (mesh->frames) + { + for (int j = 0; j < mesh->numFrames; j++) + { + mdlframe_t *frame = &mesh->frames[j]; + if (!frame->vboID) + continue; + bglDeleteBuffers(1, &frame->vboID); + frame->vboID = 0; + } + } + else if (mesh->tinyframes) + { + for (int j = 0; j < mesh->numFrames; j++) + { + tinyframe_t *frame = &mesh->tinyframes[j]; + if (!frame->vboID) + continue; + bglDeleteBuffers(1, &frame->vboID); + frame->vboID = 0; + } + } + }*/ +} diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h new file mode 100644 index 00000000..1803f4c5 --- /dev/null +++ b/src/hardware/hw_model.h @@ -0,0 +1,104 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#ifndef _HW_MODEL_H_ +#define _HW_MODEL_H_ + +#include "../doomtype.h" + +typedef struct +{ + float x, y, z; +} vector_t; + +extern vector_t vectorXaxis; +extern vector_t vectorYaxis; +extern vector_t vectorZaxis; + +void VectorRotate(vector_t *rotVec, const vector_t *axisVec, float angle); + +typedef struct +{ + float ambient[4], diffuse[4], specular[4], emissive[4]; + float shininess; + boolean spheremap; +// Texture::texture_t *texture; +// Texture::texture_t *lightmap; +} material_t; + +typedef struct +{ + material_t *material; // Pointer to the allocated 'materials' list in model_t + float *vertices; + float *normals; + float *tangents; + char *colors; + unsigned int vboID; + vector_t *polyNormals; +} mdlframe_t; + +typedef struct +{ + material_t *material; + short *vertices; + char *normals; + char *tangents; + unsigned int vboID; +} tinyframe_t; + +// Equivalent to MD3's many 'surfaces' +typedef struct mesh_s +{ + int numVertices; + int numTriangles; + + float *uvs; + float *lightuvs; + + int numFrames; + mdlframe_t *frames; + tinyframe_t *tinyframes; + unsigned short *indices; +} mesh_t; + +typedef struct tag_s +{ + char name[64]; +// matrix_t transform; +} tag_t; + +typedef struct model_s +{ + int maxNumFrames; + + int numMaterials; + material_t *materials; + int numMeshes; + mesh_t *meshes; + int numTags; + tag_t *tags; + + char *mdlFilename; + boolean unloaded; +} model_t; + +extern int numModels; +extern model_t *modelHead; + +tag_t *GetTagByName(model_t *model, char *name, int frame); +model_t *LoadModel(const char *filename, int ztag); +void UnloadModel(model_t *model); +void Optimize(model_t *model); +void GenerateVertexNormals(model_t *model); +void GeneratePolygonNormals(model_t *model, int ztag); +void CreateVBOTiny(mesh_t *mesh, tinyframe_t *frame); +void CreateVBO(mesh_t *mesh, mdlframe_t *frame); +void DeleteVBOs(model_t *model); + +#endif diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 645d934e..25852c53 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -24,9 +24,9 @@ #include #include #include "r_opengl.h" +#include "r_vbo.h" #if defined (HWRENDER) && !defined (NOROPENGL) -// for KOS: GL_TEXTURE_ENV, glAlphaFunc, glColorMask, glPolygonOffset, glReadPixels, GL_ALPHA_TEST, GL_POLYGON_OFFSET_FILL struct GLRGBAFloat { @@ -36,6 +36,7 @@ struct GLRGBAFloat GLfloat alpha; }; typedef struct GLRGBAFloat GLRGBAFloat; +static const GLubyte white[4] = { 255, 255, 255, 255 }; // ========================================================================== // CONSTANTS @@ -94,10 +95,10 @@ static GLint viewport[4]; // These need to start at 0 and be set to their number, and be reset to 0 when deleted so that Intel GPUs // can know when the textures aren't there, as textures are always considered resident in their virtual memory // TODO: Store them in a more normal way -#define SCRTEX_SCREENTEXTURE 65535 -#define SCRTEX_STARTSCREENWIPE 65534 -#define SCRTEX_ENDSCREENWIPE 65533 -#define SCRTEX_FINALSCREENTEXTURE 65532 +#define SCRTEX_SCREENTEXTURE 4294967295U +#define SCRTEX_STARTSCREENWIPE 4294967294U +#define SCRTEX_ENDSCREENWIPE 4294967293U +#define SCRTEX_FINALSCREENTEXTURE 4294967292U static GLuint screentexture = 0; static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; @@ -203,13 +204,19 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...) #define pglTranslatef glTranslatef /* Drawing Functions */ -#define pglBegin glBegin -#define pglEnd glEnd -#define pglVertex3f glVertex3f -#define pglNormal3f glNormal3f -#define pglColor4f glColor4f -#define pglColor4fv glColor4fv -#define pglTexCoord2f glTexCoord2f +#define pglColor4ubv glColor4ubv +#define pglVertexPointer glVertexPointer +#define pglNormalPointer glNormalPointer +#define pglTexCoordPointer glTexCoordPointer +#define pglDrawArrays glDrawArrays +#define pglDrawElements glDrawElements +#define pglEnableClientState glEnableClientState +#define pglDisableClientState glDisableClientState +#define pglClientActiveTexture glClientActiveTexture +#define pglGenBuffers glGenBuffers +#define pglBindBuffer glBindBuffer +#define pglBufferData glBufferData +#define pglDeleteBuffers glDeleteBuffers /* Lighting */ #define pglShadeModel glShadeModel @@ -297,20 +304,30 @@ typedef void (APIENTRY * PFNglTranslatef) (GLfloat x, GLfloat y, GLfloat z); static PFNglTranslatef pglTranslatef; /* Drawing Functions */ -typedef void (APIENTRY * PFNglBegin) (GLenum mode); -static PFNglBegin pglBegin; -typedef void (APIENTRY * PFNglEnd) (void); -static PFNglEnd pglEnd; -typedef void (APIENTRY * PFNglVertex3f) (GLfloat x, GLfloat y, GLfloat z); -static PFNglVertex3f pglVertex3f; -typedef void (APIENTRY * PFNglNormal3f) (GLfloat x, GLfloat y, GLfloat z); -static PFNglNormal3f pglNormal3f; -typedef void (APIENTRY * PFNglColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -static PFNglColor4f pglColor4f; -typedef void (APIENTRY * PFNglColor4fv) (const GLfloat *v); -static PFNglColor4fv pglColor4fv; -typedef void (APIENTRY * PFNglTexCoord2f) (GLfloat s, GLfloat t); -static PFNglTexCoord2f pglTexCoord2f; +typedef void (APIENTRY * PFNglColor4ubv) (const GLubyte *v); +static PFNglColor4ubv pglColor4ubv; +typedef void (APIENTRY * PFNglVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static PFNglVertexPointer pglVertexPointer; +typedef void (APIENTRY * PFNglNormalPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); +static PFNglNormalPointer pglNormalPointer; +typedef void (APIENTRY * PFNglTexCoordPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static PFNglTexCoordPointer pglTexCoordPointer; +typedef void (APIENTRY * PFNglDrawArrays) (GLenum mode, GLint first, GLsizei count); +static PFNglDrawArrays pglDrawArrays; +typedef void (APIENTRY * PFNglDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +static PFNglDrawElements pglDrawElements; +typedef void (APIENTRY * PFNglEnableClientState) (GLenum cap); +static PFNglEnableClientState pglEnableClientState; +typedef void (APIENTRY * PFNglDisableClientState) (GLenum cap); +static PFNglDisableClientState pglDisableClientState; +typedef void (APIENTRY * PFNglGenBuffers) (GLsizei n, GLuint *buffers); +static PFNglGenBuffers pglGenBuffers; +typedef void (APIENTRY * PFNglBindBuffer) (GLenum target, GLuint buffer); +static PFNglBindBuffer pglBindBuffer; +typedef void (APIENTRY * PFNglBufferData) (GLenum target, GLsizei size, const GLvoid *data, GLenum usage); +static PFNglBufferData pglBufferData; +typedef void (APIENTRY * PFNglDeleteBuffers) (GLsizei n, const GLuint *buffers); +static PFNglDeleteBuffers pglDeleteBuffers; /* Lighting */ typedef void (APIENTRY * PFNglShadeModel) (GLenum mode); @@ -363,6 +380,10 @@ typedef void (APIENTRY *PFNglActiveTexture) (GLenum); static PFNglActiveTexture pglActiveTexture; typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); static PFNglMultiTexCoord2f pglMultiTexCoord2f; +typedef void (APIENTRY *PFNglMultiTexCoord2fv) (GLenum target, const GLfloat *v); +static PFNglMultiTexCoord2fv pglMultiTexCoord2fv; +typedef void (APIENTRY *PFNglClientActiveTexture) (GLenum); +static PFNglClientActiveTexture pglClientActiveTexture; /* 1.2 Parms */ /* GL_CLAMP_TO_EDGE_EXT */ @@ -424,13 +445,18 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglScalef, glScalef) GETOPENGLFUNC(pglTranslatef, glTranslatef) - GETOPENGLFUNC(pglBegin, glBegin) - GETOPENGLFUNC(pglEnd, glEnd) - GETOPENGLFUNC(pglVertex3f, glVertex3f) - GETOPENGLFUNC(pglNormal3f, glNormal3f) - GETOPENGLFUNC(pglColor4f, glColor4f) - GETOPENGLFUNC(pglColor4fv, glColor4fv) - GETOPENGLFUNC(pglTexCoord2f, glTexCoord2f) + GETOPENGLFUNC(pglColor4ubv, glColor4ubv) + + GETOPENGLFUNC(pglVertexPointer, glVertexPointer) + GETOPENGLFUNC(pglNormalPointer, glNormalPointer) + GETOPENGLFUNC(pglTexCoordPointer, glTexCoordPointer) + GETOPENGLFUNC(pglDrawArrays, glDrawArrays) + GETOPENGLFUNC(pglDrawElements, glDrawElements) + GETOPENGLFUNC(pglEnableClientState, glEnableClientState) + GETOPENGLFUNC(pglDisableClientState, glDisableClientState) + GETOPENGLFUNC(pglClientActiveTexture, glClientActiveTexture) + if (!pglClientActiveTexture) + GETOPENGLFUNC(pglClientActiveTexture, glClientActiveTextureARB) GETOPENGLFUNC(pglShadeModel, glShadeModel) GETOPENGLFUNC(pglLightfv, glLightfv) @@ -471,49 +497,8 @@ boolean GLEXT_shaders = false; // hw_glob.h INT32 gl_leveltime = 0; -//#define GL_RETAINED_MODE // Immediate mode is faster. Go fucking figure. #define USE_SHADERS -typedef void (APIENTRY *PFNglDrawArrays) (GLenum, GLint, GLsizei); -typedef void (APIENTRY *PFNglDrawElements) (GLenum, GLsizei, GLenum, const GLvoid*); -typedef void (APIENTRY *PFNglVertexAttribPointer) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); -typedef void (APIENTRY *PFNglEnableClientState) (GLenum); -typedef void (APIENTRY *PFNglDisableClientState) (GLenum); -typedef void (APIENTRY *PFNglBindVertexArray) (GLuint); -typedef void (APIENTRY *PFNglGenVertexArrays) (GLsizei, GLuint*); -typedef void (APIENTRY *PFNglGenBuffers) (GLsizei, GLuint*); -typedef void (APIENTRY *PFNglBindBuffer) (GLenum, GLuint); -typedef void (APIENTRY *PFNglBufferData) (GLenum, GLsizeiptr, GLvoid*, GLenum); -typedef void (APIENTRY *PFNglBufferSubData) (GLenum, GLintptr, GLsizeiptr, GLvoid*); -typedef void (APIENTRY *PFNglDeleteBuffers) (GLsizei, GLuint*); -typedef void (APIENTRY *PFNglDeleteVertexArrays) (GLsizei, GLuint*); -typedef void (APIENTRY *PFNglEnableVertexAttribArray) (GLuint); -typedef void (APIENTRY *PFNglDisableVertexAttribArray) (GLuint); - -static PFNglDrawArrays pglDrawArrays; -static PFNglDrawElements pglDrawElements; -static PFNglVertexAttribPointer pglVertexAttribPointer; -static PFNglEnableClientState pglEnableClientState; -static PFNglDisableClientState pglDisableClientState; -static PFNglBindVertexArray pglBindVertexArray; -static PFNglGenVertexArrays pglGenVertexArrays; -static PFNglGenBuffers pglGenBuffers; -static PFNglBindBuffer pglBindBuffer; -static PFNglBufferData pglBufferData; -static PFNglBufferSubData pglBufferSubData; -static PFNglDeleteBuffers pglDeleteBuffers; -static PFNglDeleteVertexArrays pglDeleteVertexArrays; -static PFNglEnableVertexAttribArray pglEnableVertexAttribArray; -static PFNglDisableVertexAttribArray pglDisableVertexAttribArray; - -typedef void (APIENTRY *PFNglVertexPointer) (GLint, GLenum, GLsizei, const GLvoid*); -typedef void (APIENTRY *PFNglNormalPointer) (GLenum, GLsizei, const GLvoid*); -typedef void (APIENTRY *PFNglTexCoordPointer) (GLint, GLenum, GLsizei, const GLvoid*); - -static PFNglVertexPointer pglVertexPointer; -static PFNglNormalPointer pglNormalPointer; -static PFNglTexCoordPointer pglTexCoordPointer; - // shaders #ifdef USE_SHADERS @@ -667,39 +652,18 @@ static char *fragment_shaders[] = { "}\0", }; -// Macro to reduce boilerplate code -#define BUFFER_OFFSET(i) ((void*)(i)) - #endif // USE_SHADERS -static GLuint gl_vertexarrayobject; -static GLuint gl_vertexbuffer; - void SetupGLFunc4(void) { pglActiveTexture = GetGLFunc("glActiveTexture"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); - - // 4.x - pglDrawArrays = GetGLFunc("glDrawArrays"); - pglDrawElements = GetGLFunc("glDrawElements"); - pglVertexAttribPointer = GetGLFunc("glVertexAttribPointer"); - pglEnableClientState = GetGLFunc("glEnableClientState"); - pglDisableClientState = GetGLFunc("glDisableClientState"); - pglBindVertexArray = GetGLFunc("glBindVertexArray"); - pglGenVertexArrays = GetGLFunc("glGenVertexArrays"); + pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); + pglMultiTexCoord2fv = GetGLFunc("glMultiTexCoord2fv"); pglGenBuffers = GetGLFunc("glGenBuffers"); pglBindBuffer = GetGLFunc("glBindBuffer"); pglBufferData = GetGLFunc("glBufferData"); - pglBufferSubData = GetGLFunc("glBufferSubData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); - pglDeleteVertexArrays = GetGLFunc("glDeleteVertexArrays"); - pglEnableVertexAttribArray = GetGLFunc("glEnableVertexAttribArray"); - pglDisableVertexAttribArray = GetGLFunc("glDisableVertexAttribArray"); - - pglVertexPointer = GetGLFunc("glVertexPointer"); - pglNormalPointer = GetGLFunc("glNormalPointer"); - pglTexCoordPointer = GetGLFunc("glTexCoordPointer"); #ifdef USE_SHADERS pglCreateShader = GetGLFunc("glCreateShader"); @@ -881,6 +845,12 @@ void SetModelView(GLint w, GLint h) // -----------------+ void SetStates(void) { +#ifdef GL_LIGHT_MODEL_AMBIENT + GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; +#endif + + pglShadeModel(GL_SMOOTH); // iterate vertice colors + pglEnable(GL_TEXTURE_2D); // two-dimensional texturing pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); @@ -904,25 +874,16 @@ void SetStates(void) pglPolygonOffset(-1.0f, -1.0f); + // Lighting for models +#ifdef GL_LIGHT_MODEL_AMBIENT + pglLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightDiffuse); + pglEnable(GL_LIGHT0); +#endif + // bp : when no t&l :) pglLoadIdentity(); pglScalef(1.0f, 1.0f, -1.0f); pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer) - - // jimita -#ifndef GL_RETAINED_MODE - if (!GLEXT_legacy) - I_Error("GPU does not support legacy specifications"); -#endif - - pglDeleteVertexArrays(1, &gl_vertexarrayobject); - pglDeleteBuffers(1, &gl_vertexbuffer); - - pglGenVertexArrays(1, &gl_vertexarrayobject); - pglGenBuffers(1, &gl_vertexbuffer); - - pglBindVertexArray(gl_vertexarrayobject); - pglBindBuffer(GL_ARRAY_BUFFER, gl_vertexbuffer); } @@ -1100,6 +1061,8 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, SetBlend(DepthMask ? PF_Occlude | CurrentPolyFlags : CurrentPolyFlags&~PF_Occlude); pglClear(ClearMask); + pglEnableClientState(GL_VERTEX_ARRAY); // We always use this one + pglEnableClientState(GL_TEXTURE_COORD_ARRAY); // And mostly this one, too } @@ -1110,26 +1073,35 @@ EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1, F2DCoord * v2, RGBA_t Color) { - GLRGBAFloat c; - //GL_DBG_Printf("DrawLine() (%f %f %f) %d\n", v1->x, -v1->y, -v1->z, v1->argb); + GLfloat p[12]; + GLfloat dx, dy; + GLfloat angle; // BP: we should reflect the new state in our variable //SetBlend(PF_Modulated|PF_NoTexture); pglDisable(GL_TEXTURE_2D); - c.red = byte2float[Color.s.red]; - c.green = byte2float[Color.s.green]; - c.blue = byte2float[Color.s.blue]; - c.alpha = byte2float[Color.s.alpha]; + // This is the preferred, 'modern' way of rendering lines -- creating a polygon. + if (fabsf(v2->x - v1->x) > FLT_EPSILON) + angle = (float)atan((v2->y-v1->y)/(v2->x-v1->x)); + else + angle = (float)N_PI_DEMI; + dx = (float)sin(angle) / (float)screen_width; + dy = (float)cos(angle) / (float)screen_height; - pglColor4fv(&c.red); // is in RGBA float format - pglBegin(GL_LINES); - pglVertex3f(v1->x, -v1->y, 1.0f); - pglVertex3f(v2->x, -v2->y, 1.0f); - pglEnd(); + p[0] = v1->x - dx; p[1] = -(v1->y + dy); p[2] = 1; + p[3] = v2->x - dx; p[4] = -(v2->y + dy); p[5] = 1; + p[6] = v2->x + dx; p[7] = -(v2->y - dy); p[8] = 1; + p[9] = v1->x + dx; p[10] = -(v1->y - dy); p[11] = 1; + pglDisableClientState(GL_TEXTURE_COORD_ARRAY); + pglColor4ubv((GLubyte*)&Color.s); + pglVertexPointer(3, GL_FLOAT, 0, p); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + pglEnableClientState(GL_TEXTURE_COORD_ARRAY); pglEnable(GL_TEXTURE_2D); } @@ -1176,7 +1148,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) break; case PF_Substractive & PF_Blending: // good for shadow - // not realy but what else ? + // not really but what else ? pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); pglAlphaFunc(GL_NOTEQUAL, 0.0f); break; @@ -1240,7 +1212,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) if (oglflags & GLF_NOTEXENV) { if (!(PolyFlags & PF_Modulated)) - pglColor4f(1.0f, 1.0f, 1.0f, 1.0f); + pglColor4ubv(white); } else #endif @@ -1585,9 +1557,6 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI { static GLRGBAFloat mix = {0,0,0,0}; static GLRGBAFloat fade = {0,0,0,0}; -#ifndef GL_RETAINED_MODE - FUINT i; -#endif SetBlend(PolyFlags); //TODO: inline (#pragma..) @@ -1603,7 +1572,7 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI mix.blue = byte2float[pSurf->PolyColor.s.blue]; mix.alpha = byte2float[pSurf->PolyColor.s.alpha]; - pglColor4fv(&mix.red); + pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); } // Fade color @@ -1616,24 +1585,9 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI // jimita load_shaders(pSurf, &mix, &fade); -#ifdef GL_RETAINED_MODE - pglBufferData(GL_ARRAY_BUFFER, sizeof(FOutVector)*iNumPts, &pOutVerts[0].x, GL_STATIC_DRAW); - - pglEnableClientState(GL_VERTEX_ARRAY); - pglEnableClientState(GL_TEXTURE_COORD_ARRAY); - - pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), BUFFER_OFFSET(0)); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), BUFFER_OFFSET(sizeof(FLOAT)*3)); + pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].sow); pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts); -#else - pglBegin(GL_TRIANGLE_FAN); - for (i = 0; i < iNumPts; i++) - { - pglTexCoord2f(pOutVerts[i].sow, pOutVerts[i].tow); - pglVertex3f(pOutVerts[i].x, pOutVerts[i].y, pOutVerts[i].z); - } - pglEnd(); -#endif if (PolyFlags & PF_RemoveYWrap) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -1644,11 +1598,6 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI if (PolyFlags & PF_ForceWrapY) Clamp2D(GL_TEXTURE_WRAP_T); -#ifdef GL_RETAINED_MODE - pglDisableClientState(GL_VERTEX_ARRAY); - pglDisableClientState(GL_TEXTURE_COORD_ARRAY); -#endif - #ifdef USE_SHADERS pglUseProgram(0); #endif @@ -1723,17 +1672,225 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) } } -static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, INT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) +static float *vertBuffer = NULL; +static float *normBuffer = NULL; +static size_t lerpBufferSize = 0; +static short *vertTinyBuffer = NULL; +static char *normTinyBuffer = NULL; +static size_t lerpTinyBufferSize = 0; + +// Static temporary buffer for doing frame interpolation +// 'size' is the vertex size +static void AllocLerpBuffer(size_t size) { - INT32 val, count, pindex; - GLfloat s, t; + if (lerpBufferSize >= size) + return; - float pol = 0.0f; - float scalex = scale, scaley = scale, scalez = scale; + if (vertBuffer != NULL) + free(vertBuffer); + if (normBuffer != NULL) + free(normBuffer); + + lerpBufferSize = size; + vertBuffer = malloc(lerpBufferSize); + normBuffer = malloc(lerpBufferSize); +} + +// Static temporary buffer for doing frame interpolation +// 'size' is the vertex size +static void AllocLerpTinyBuffer(size_t size) +{ + if (lerpTinyBufferSize >= size) + return; + + if (vertTinyBuffer != NULL) + free(vertTinyBuffer); + + if (normTinyBuffer != NULL) + free(normTinyBuffer); + + lerpTinyBufferSize = size; + vertTinyBuffer = malloc(lerpTinyBufferSize); + normTinyBuffer = malloc(lerpTinyBufferSize / 2); +} + +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif + +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif + +static void CreateModelVBO(mesh_t *mesh, mdlframe_t *frame) +{ + int bufferSize = sizeof(vbo64_t)*mesh->numTriangles * 3; + vbo64_t *buffer = (vbo64_t*)malloc(bufferSize); + vbo64_t *bufPtr = buffer; + + float *vertPtr = frame->vertices; + float *normPtr = frame->normals; + float *tanPtr = frame->tangents; + float *uvPtr = mesh->uvs; + float *lightPtr = mesh->lightuvs; + char *colorPtr = frame->colors; + + int i; + for (i = 0; i < mesh->numTriangles * 3; i++) + { + bufPtr->x = *vertPtr++; + bufPtr->y = *vertPtr++; + bufPtr->z = *vertPtr++; + + bufPtr->nx = *normPtr++; + bufPtr->ny = *normPtr++; + bufPtr->nz = *normPtr++; + + bufPtr->s0 = *uvPtr++; + bufPtr->t0 = *uvPtr++; + + if (tanPtr != NULL) + { + bufPtr->tan0 = *tanPtr++; + bufPtr->tan1 = *tanPtr++; + bufPtr->tan2 = *tanPtr++; + } + + if (lightPtr != NULL) + { + bufPtr->s1 = *lightPtr++; + bufPtr->t1 = *lightPtr++; + } + + if (colorPtr) + { + bufPtr->r = *colorPtr++; + bufPtr->g = *colorPtr++; + bufPtr->b = *colorPtr++; + bufPtr->a = *colorPtr++; + } + else + { + bufPtr->r = 255; + bufPtr->g = 255; + bufPtr->b = 255; + bufPtr->a = 255; + } + + bufPtr++; + } + + pglGenBuffers(1, &frame->vboID); + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW); + free(buffer); +} + +static void CreateModelVBOTiny(mesh_t *mesh, tinyframe_t *frame) +{ + int bufferSize = sizeof(vbotiny_t)*mesh->numTriangles * 3; + vbotiny_t *buffer = (vbotiny_t*)malloc(bufferSize); + vbotiny_t *bufPtr = buffer; + + short *vertPtr = frame->vertices; + char *normPtr = frame->normals; + float *uvPtr = mesh->uvs; + char *tanPtr = frame->tangents; + + int i; + for (i = 0; i < mesh->numVertices; i++) + { + bufPtr->x = *vertPtr++; + bufPtr->y = *vertPtr++; + bufPtr->z = *vertPtr++; + + bufPtr->nx = *normPtr++; + bufPtr->ny = *normPtr++; + bufPtr->nz = *normPtr++; + + bufPtr->s0 = *uvPtr++; + bufPtr->t0 = *uvPtr++; + + if (tanPtr) + { + bufPtr->tanx = *tanPtr++; + bufPtr->tany = *tanPtr++; + bufPtr->tanz = *tanPtr++; + } + + bufPtr++; + } + + pglGenBuffers(1, &frame->vboID); + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW); + free(buffer); +} + +EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) +{ + int i; + for (i = 0; i < model->numMeshes; i++) + { + mesh_t *mesh = &model->meshes[i]; + + if (mesh->frames) + { + int j; + for (j = 0; j < model->meshes[i].numFrames; j++) + { + mdlframe_t *frame = &mesh->frames[j]; + if (frame->vboID) + pglDeleteBuffers(1, &frame->vboID); + frame->vboID = 0; + CreateModelVBO(mesh, frame); + } + } + else if (mesh->tinyframes) + { + int j; + for (j = 0; j < model->meshes[i].numFrames; j++) + { + tinyframe_t *frame = &mesh->tinyframes[j]; + if (frame->vboID) + pglDeleteBuffers(1, &frame->vboID); + frame->vboID = 0; + CreateModelVBOTiny(mesh, frame); + } + } + } +} + +// Macro to +#define BUFFER_OFFSET(i) ((void*)(i)) + +static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) +{ static GLRGBAFloat mix = {0,0,0,0}; static GLRGBAFloat fade = {0,0,0,0}; +#ifdef GL_LIGHT_MODEL_AMBIENT + GLfloat ambient[4]; + GLfloat diffuse[4]; +#endif + + float pol = 0.0f; + float scalex, scaley, scalez; + + boolean useTinyFrames; + + int i; + + // Because Otherwise, scaling the screen negatively vertically breaks the lighting + GLfloat LightPos[] = {0.0f, 1.0f, 0.0f, 0.0f}; + + // Affect input model scaling + scale *= 0.5f; + scalex = scale; + scaley = scale; + scalez = scale; + if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length { UINT32 newtime = (duration - tics); // + 1; @@ -1752,6 +1909,25 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, mix.blue = byte2float[Surface->PolyColor.s.blue]; mix.alpha = byte2float[Surface->PolyColor.s.alpha]; +#ifdef GL_LIGHT_MODEL_AMBIENT + ambient[0] = (mix.red/255.0f); + ambient[1] = (mix.green/255.0f); + ambient[2] = (mix.blue/255.0f); + ambient[3] = (mix.alpha/255.0f); + + diffuse[0] = (mix.red/255.0f); + diffuse[1] = (mix.green/255.0f); + diffuse[2] = (mix.blue/255.0f); + diffuse[3] = (mix.alpha/255.0f); + + if (ambient[0] > 0.75f) + ambient[0] = 0.75f; + if (ambient[1] > 0.75f) + ambient[1] = 0.75f; + if (ambient[2] > 0.75f) + ambient[2] = 0.75f; +#endif + if (mix.alpha < 1) SetBlend(PF_Translucent|PF_Modulated); else @@ -1762,151 +1938,158 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; - pglEnable(GL_CULL_FACE); + // jimita + load_shaders(Surface, &mix, &fade); + pglEnable(GL_CULL_FACE); + pglEnable(GL_NORMALIZE); + +#ifdef USE_FTRANSFORM_MIRROR + // flipped is if the object is flipped + // pos->flip is if the screen is flipped vertically + // pos->mirror is if the screen is flipped horizontally + // XOR all the flips together to figure out what culling to use! + { + boolean reversecull = (flipped ^ pos->flip ^ pos->mirror); + if (reversecull) + pglCullFace(GL_FRONT); + else + pglCullFace(GL_BACK); + } +#else // pos->flip is if the screen is flipped too if (flipped != pos->flip) // If either are active, but not both, invert the model's culling pglCullFace(GL_FRONT); else pglCullFace(GL_BACK); +#endif - pglPushMatrix(); + pglLightfv(GL_LIGHT0, GL_POSITION, LightPos); + pglShadeModel(GL_SMOOTH); +#ifdef GL_LIGHT_MODEL_AMBIENT + pglEnable(GL_LIGHTING); + pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); + pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); +#endif + + pglPushMatrix(); // should be the same as glLoadIdentity pglTranslatef(pos->x, pos->z, pos->y); if (flipped) scaley = -scaley; - pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); +#ifdef USE_FTRANSFORM_ANGLEZ + pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart +#endif pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f); + pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); - // jimita - load_shaders(Surface, &mix, &fade); + pglScalef(scalex, scaley, scalez); - pglVertexPointer(3, GL_FLOAT, sizeof(FOutVectorMD2), BUFFER_OFFSET(0)); - pglNormalPointer(GL_FLOAT, sizeof(FOutVectorMD2), BUFFER_OFFSET(sizeof(float)*3)); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVectorMD2), BUFFER_OFFSET(sizeof(float)*6)); + useTinyFrames = model->meshes[0].tinyframes != NULL; - val = *gl_cmd_buffer++; + if (useTinyFrames) + pglScalef(1 / 64.0f, 1 / 64.0f, 1 / 64.0f); - while (val != 0) + pglEnableClientState(GL_NORMAL_ARRAY); + + for (i = 0; i < model->numMeshes; i++) { -#ifdef GL_RETAINED_MODE - FOutVectorMD2 *polydata; - int polyindex = 0; -#endif - int drawarraytype; + mesh_t *mesh = &model->meshes[i]; - if (val < 0) + if (useTinyFrames) { - drawarraytype = GL_TRIANGLE_FAN; - count = -val; - } - else - { - drawarraytype = GL_TRIANGLE_STRIP; - count = val; - } + tinyframe_t *frame = &mesh->tinyframes[frameIndex % mesh->numFrames]; + tinyframe_t *nextframe = NULL; -#ifndef GL_RETAINED_MODE - pglBegin(drawarraytype); -#else - polydata = malloc(sizeof(FOutVectorMD2) * count); -#endif - - while (count--) - { - s = *(float *) gl_cmd_buffer++; - t = *(float *) gl_cmd_buffer++; - pindex = *gl_cmd_buffer++; - -#ifdef GL_RETAINED_MODE - polydata[polyindex].s = s; - polydata[polyindex].t = t; -#else - pglTexCoord2f(s, t); -#endif + if (nextFrameIndex != -1) + nextframe = &mesh->tinyframes[nextFrameIndex % mesh->numFrames]; if (!nextframe || fpclassify(pol) == FP_ZERO) { -#ifdef GL_RETAINED_MODE - polydata[polyindex].vx = frame->vertices[pindex].vertex[0]*scalex/2.0f; - polydata[polyindex].vy = frame->vertices[pindex].vertex[1]*scaley/2.0f; - polydata[polyindex].vz = frame->vertices[pindex].vertex[2]*scalez/2.0f; - - polydata[polyindex].nx = frame->vertices[pindex].normal[0]; - polydata[polyindex].ny = frame->vertices[pindex].normal[1]; - polydata[polyindex].nz = frame->vertices[pindex].normal[2]; - - polyindex++; -#else - - pglNormal3f(frame->vertices[pindex].normal[0], - frame->vertices[pindex].normal[1], - frame->vertices[pindex].normal[2]); - - pglVertex3f(frame->vertices[pindex].vertex[0]*scalex/2.0f, - frame->vertices[pindex].vertex[1]*scaley/2.0f, - frame->vertices[pindex].vertex[2]*scalez/2.0f); -#endif + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0)); + pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3)); + pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6)); + pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); + pglBindBuffer(GL_ARRAY_BUFFER, 0); } else { - // Interpolate - float px1 = frame->vertices[pindex].vertex[0]*scalex/2.0f; - float px2 = nextframe->vertices[pindex].vertex[0]*scalex/2.0f; - float py1 = frame->vertices[pindex].vertex[1]*scaley/2.0f; - float py2 = nextframe->vertices[pindex].vertex[1]*scaley/2.0f; - float pz1 = frame->vertices[pindex].vertex[2]*scalez/2.0f; - float pz2 = nextframe->vertices[pindex].vertex[2]*scalez/2.0f; - float nx1 = frame->vertices[pindex].normal[0]; - float nx2 = nextframe->vertices[pindex].normal[0]; - float ny1 = frame->vertices[pindex].normal[1]; - float ny2 = nextframe->vertices[pindex].normal[1]; - float nz1 = frame->vertices[pindex].normal[2]; - float nz2 = nextframe->vertices[pindex].normal[2]; + short *vertPtr; + char *normPtr; + int j = 0; -#ifdef GL_RETAINED_MODE - polydata[polyindex].vx = (px1 + pol * (px2 - px1)); - polydata[polyindex].vy = (py1 + pol * (py2 - py1)); - polydata[polyindex].vz = (pz1 + pol * (pz2 - pz1)); + // Dangit, I soooo want to do this in a GLSL shader... + AllocLerpTinyBuffer(mesh->numVertices * sizeof(short) * 3); + vertPtr = vertTinyBuffer; + normPtr = normTinyBuffer; - polydata[polyindex].nx = (nx1 + pol * (nx2 - nx1)); - polydata[polyindex].ny = (ny1 + pol * (ny2 - ny1)); - polydata[polyindex].nz = (nz1 + pol * (nz2 - nz1)); + for (j = 0; j < mesh->numVertices * 3; j++) + { + // Interpolate + *vertPtr++ = (short)(frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j]))); + *normPtr++ = (char)(frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j]))); + } - polyindex++; -#else - pglNormal3f((nx1 + pol * (nx2 - nx1)), - (ny1 + pol * (ny2 - ny1)), - (nz1 + pol * (nz2 - nz1))); - pglVertex3f((px1 + pol * (px2 - px1)), - (py1 + pol * (py2 - py1)), - (pz1 + pol * (pz2 - pz1))); -#endif + pglVertexPointer(3, GL_SHORT, 0, vertTinyBuffer); + pglNormalPointer(GL_BYTE, 0, normTinyBuffer); + pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); + pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); } } + else + { + mdlframe_t *frame = &mesh->frames[frameIndex % mesh->numFrames]; + mdlframe_t *nextframe = NULL; -#ifdef GL_RETAINED_MODE - pglEnableClientState(GL_VERTEX_ARRAY); - pglEnableClientState(GL_NORMAL_ARRAY); - pglEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (nextFrameIndex != -1) + nextframe = &mesh->frames[nextFrameIndex % mesh->numFrames]; - pglBufferData(GL_ARRAY_BUFFER, sizeof(FOutVectorMD2)*polyindex, &polydata[0].vx, GL_DYNAMIC_DRAW); + if (!nextframe || pol == 0.0f) + { + // Zoom! Take advantage of just shoving the entire arrays to the GPU. + pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID); + pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0)); + pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3)); + pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6)); - pglDrawArrays(drawarraytype, 0, polyindex); + pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3); + pglBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + float *vertPtr; + float *normPtr; + int j = 0; - free(polydata); -#else - pglEnd(); -#endif + // Dangit, I soooo want to do this in a GLSL shader... + AllocLerpBuffer(mesh->numVertices * sizeof(float) * 3); + vertPtr = vertBuffer; + normPtr = normBuffer; - val = *gl_cmd_buffer++; + for (j = 0; j < mesh->numVertices * 3; j++) + { + // Interpolate + *vertPtr++ = frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j])); + *normPtr++ = frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j])); + } + + pglVertexPointer(3, GL_FLOAT, 0, vertBuffer); + pglNormalPointer(GL_FLOAT, 0, normBuffer); + pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); + pglDrawArrays(GL_TRIANGLES, 0, mesh->numVertices); + } + } } - pglPopMatrix(); - pglDisable(GL_CULL_FACE); - - pglDisableClientState(GL_VERTEX_ARRAY); pglDisableClientState(GL_NORMAL_ARRAY); - pglDisableClientState(GL_TEXTURE_COORD_ARRAY); + + pglPopMatrix(); // should be the same as glLoadIdentity +#ifdef GL_LIGHT_MODEL_AMBIENT + pglDisable(GL_LIGHTING); +#endif + pglShadeModel(GL_FLAT); + pglDisable(GL_CULL_FACE); + pglDisable(GL_NORMALIZE); #ifdef USE_SHADERS pglUseProgram(0); @@ -1914,15 +2097,11 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, } // -----------------+ -// HWRAPI DrawMD2 : Draw an MD2 model with glcommands +// HWRAPI DrawModel : Draw a model // -----------------+ -EXPORT void HWRAPI(DrawMD2) ( - INT32 *gl_cmd_buffer, md2_frame_t *frame, - INT32 duration, INT32 tics, md2_frame_t *nextframe, - FTransform *pos, float scale, UINT8 flipped, - FSurfaceInfo *Surface) // jimita 17032019 +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) { - DrawMD2Ex(gl_cmd_buffer, frame, duration, tics, nextframe, pos, scale, flipped, Surface); + DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, Surface); } // -----------------+ @@ -1930,14 +2109,19 @@ EXPORT void HWRAPI(DrawMD2) ( // -----------------+ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) { - static INT32 special_splitscreen; + static boolean special_splitscreen; pglLoadIdentity(); if (stransform) { - boolean fovx90; // keep a trace of the transformation for md2 memcpy(&md2_transform, stransform, sizeof (md2_transform)); +#ifdef USE_FTRANSFORM_MIRROR + // mirroring from Kart + if (stransform->mirror) + pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); + else +#endif if (stransform->flip) pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); else @@ -1949,8 +2133,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); - fovx90 = stransform->fovxangle > 0.0f && fabsf(stransform->fovxangle - 90.0f) < 0.5f; - special_splitscreen = (stransform->splitscreen && fovx90); + special_splitscreen = (stransform->splitscreen == 1 && stransform->fovxangle == 90.0f); if (special_splitscreen) GLPerspective(53.13f, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5) else @@ -2001,7 +2184,15 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) float xfix, yfix; INT32 texsize = 2048; - // Use a power of two texture, dammit + const float blackBack[16] = + { + -16.0f, -16.0f, 6.0f, + -16.0f, 16.0f, 6.0f, + 16.0f, 16.0f, 6.0f, + 16.0f, -16.0f, 6.0f + }; + + // Use a power of two texture if(screen_width <= 1024) texsize = 1024; if(screen_width <= 512) @@ -2013,43 +2204,60 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) pglDisable(GL_DEPTH_TEST); pglDisable(GL_BLEND); - pglBegin(GL_QUADS); - // Draw a black square behind the screen texture, - // so nothing shows through the edges - pglColor4f(1.0f, 1.0f, 1.0f, 1.0f); - pglVertex3f(-16.0f, -16.0f, 6.0f); - pglVertex3f(-16.0f, 16.0f, 6.0f); - pglVertex3f(16.0f, 16.0f, 6.0f); - pglVertex3f(16.0f, -16.0f, 6.0f); + // Draw a black square behind the screen texture, + // so nothing shows through the edges + pglColor4ubv(white); - for(x=0;xprev = (*itemHead)->next = NULL; + } + else + { + listitem_t *tail; + tail = *itemHead; + + while (tail->next != NULL) + tail = tail->next; + + tail->next = item; + + tail->next->prev = tail; + + item->next = NULL; + } +} + +// +// ListAddFront +// +// Adds an item to the front of the list +// (This is much faster) +// +void ListAddFront(void *pItem, listitem_t **itemHead) +{ + listitem_t *item = (listitem_t*)pItem; + + if (*itemHead == NULL) + { + *itemHead = item; + (*itemHead)->prev = (*itemHead)->next = NULL; + } + else + { + (*itemHead)->prev = item; + item->next = (*itemHead); + item->prev = NULL; + *itemHead = item; + } +} + +// +// ListAddBefore +// +// Adds an item before the item specified in the list +// +void ListAddBefore(void *pItem, void *pSpot, listitem_t **itemHead) +{ + listitem_t *item = (listitem_t*)pItem; + listitem_t *spot = (listitem_t*)pSpot; + + listitem_t *prev = spot->prev; + + if (!prev) + ListAddFront(pItem, itemHead); + else + { + item->next = spot; + spot->prev = item; + item->prev = prev; + prev->next = item; + } +} + +// +// ListAddAfter +// +// Adds an item after the item specified in the list +// +void ListAddAfter(void *pItem, void *pSpot, listitem_t **itemHead) +{ + listitem_t *item = (listitem_t*)pItem; + listitem_t *spot = (listitem_t*)pSpot; + + listitem_t *next = spot->next; + + if (!next) + ListAdd(pItem, itemHead); + else + { + item->prev = spot; + spot->next = item; + item->next = next; + next->prev = item; + } +} + +// +// ListRemove +// +// Take an item out of the list and free its memory. +// +void ListRemove(void *pItem, listitem_t **itemHead) +{ + listitem_t *item = (listitem_t*)pItem; + + if (item == *itemHead) // Start of list + { + *itemHead = item->next; + + if (*itemHead) + (*itemHead)->prev = NULL; + } + else if (item->next == NULL) // end of list + { + item->prev->next = NULL; + } + else // Somewhere in between + { + item->prev->next = item->next; + item->next->prev = item->prev; + } + + Z_Free (item); +} + +// +// ListRemoveAll +// +// Removes all items from the list, freeing their memory. +// +void ListRemoveAll(listitem_t **itemHead) +{ + listitem_t *item; + listitem_t *next; + for (item = *itemHead; item; item = next) + { + next = item->next; + ListRemove(item, itemHead); + } +} + +// +// ListRemoveNoFree +// +// Take an item out of the list, but don't free its memory. +// +void ListRemoveNoFree(void *pItem, listitem_t **itemHead) +{ + listitem_t *item = (listitem_t*)pItem; + + if (item == *itemHead) // Start of list + { + *itemHead = item->next; + + if (*itemHead) + (*itemHead)->prev = NULL; + } + else if (item->next == NULL) // end of list + { + item->prev->next = NULL; + } + else // Somewhere in between + { + item->prev->next = item->next; + item->next->prev = item->prev; + } +} + +// +// ListGetCount +// +// Counts the # of items in a list +// Should not be used in performance-minded code +// +unsigned int ListGetCount(void *itemHead) +{ + listitem_t *item = (listitem_t*)itemHead; + + unsigned int count = 0; + for (; item; item = item->next) + count++; + + return count; +} + +// +// ListGetByIndex +// +// Gets an item in the list by its index +// Should not be used in performance-minded code +// +listitem_t *ListGetByIndex(void *itemHead, unsigned int index) +{ + listitem_t *head = (listitem_t*)itemHead; + unsigned int count = 0; + listitem_t *node; + for (node = head; node; node = node->next) + { + if (count == index) + return node; + + count++; + } + + return NULL; +} + diff --git a/src/hardware/u_list.h b/src/hardware/u_list.h new file mode 100644 index 00000000..7e9a3cab --- /dev/null +++ b/src/hardware/u_list.h @@ -0,0 +1,29 @@ +/* + From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com ) + An experimental work-in-progress. + + Donated to Sonic Team Junior and adapted to work with + Sonic Robo Blast 2. The license of this code matches whatever + the licensing is for Sonic Robo Blast 2. +*/ + +#ifndef _U_LIST_H_ +#define _U_LIST_H_ + +typedef struct listitem_s +{ + struct listitem_s *next; + struct listitem_s *prev; +} listitem_t; + +void ListAdd(void *pItem, listitem_t **itemHead); +void ListAddFront(void *pItem, listitem_t **itemHead); +void ListAddBefore(void *pItem, void *pSpot, listitem_t **itemHead); +void ListAddAfter(void *pItem, void *pSpot, listitem_t **itemHead); +void ListRemove(void *pItem, listitem_t **itemHead); +void ListRemoveAll(listitem_t **itemHead); +void ListRemoveNoFree(void *pItem, listitem_t **itemHead); +unsigned int ListGetCount(void *itemHead); +listitem_t *ListGetByIndex(void *itemHead, unsigned int index); + +#endif diff --git a/src/m_fixed.c b/src/m_fixed.c index d45bb70b..538da2fd 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -411,6 +411,19 @@ boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2) return false; } +// ClosestPointOnVector +// +// Similar to ClosestPointOnLine, but uses a vector instead of two points. +// +void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_t *out) +{ + fixed_t t = FV3_Dot(dir, p); + + // Return the point on the line closest + FV3_MulEx(dir, t, out); + return; +} + fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2) { return (FixedMul(a_1->x, a_2->x) + FixedMul(a_1->y, a_2->y) + FixedMul(a_1->z, a_2->z)); @@ -519,7 +532,7 @@ vector3_t *FV3_Point2Vec (const vector3_t *point1, const vector3_t *point2, vect // // Calculates the normal of a polygon. // -void FV3_Normal (const vector3_t *a_triangle, vector3_t *a_normal) +fixed_t FV3_Normal (const vector3_t *a_triangle, vector3_t *a_normal) { vector3_t a_1; vector3_t a_2; @@ -529,7 +542,28 @@ void FV3_Normal (const vector3_t *a_triangle, vector3_t *a_normal) FV3_Cross(&a_1, &a_2, a_normal); - FV3_NormalizeEx(a_normal, a_normal); + return FV3_NormalizeEx(a_normal, a_normal); +} + +// +// Strength +// +// Measures the 'strength' of a vector in a particular direction. +// +fixed_t FV3_Strength(const vector3_t *a_1, const vector3_t *dir) +{ + vector3_t normal; + fixed_t dist = FV3_NormalizeEx(a_1, &normal); + fixed_t dot = FV3_Dot(&normal, dir); + + FV3_ClosestPointOnVector(dir, a_1, &normal); + + dist = FV3_Magnitude(&normal); + + if (dot < 0) // Not facing same direction, so negate result. + dist = -dist; + + return dist; } // diff --git a/src/m_fixed.h b/src/m_fixed.h index 4609913b..8145a691 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -394,9 +394,11 @@ boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2); fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2); vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o); vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vector3_t *out); +void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_t *out); void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result); vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o); -void FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal); +fixed_t FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal); +fixed_t FV3_Strength(const vector3_t *a_1, const vector3_t *dir); fixed_t FV3_PlaneDistance(const vector3_t *a_normal, const vector3_t *a_point); boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_line, vector3_t *a_normal, fixed_t *originDistance); fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector); diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index e4377217..a8b88165 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -227,6 +227,10 @@ + + + + @@ -365,8 +369,12 @@ + + + + @@ -478,4 +486,4 @@ - \ No newline at end of file + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index d67ac630..d9caf5ce 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -246,6 +246,18 @@ Hw_Hardware + + Hw_Hardware + + + Hw_Hardware + + + Hw_Hardware + + + Hw_Hardware + I_Interface @@ -623,10 +635,22 @@ Hw_Hardware + + + Hw_Hardware + + + Hw_Hardware + + + Hw_Hardware Hw_Hardware + + Hw_Hardware + I_Interface @@ -894,4 +918,4 @@ SDLApp - \ No newline at end of file + diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 5ee984b2..22faeb8d 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -88,7 +88,8 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); GETFUNC(GetTextureUsed); - GETFUNC(DrawMD2); + GETFUNC(DrawModel); + GETFUNC(CreateModelVBOs); GETFUNC(SetTransform); GETFUNC(GetRenderVersion); GETFUNC(PostImgRedraw); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d0c34d93..caf02049 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1485,7 +1485,8 @@ void I_StartupGraphics(void) HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); - HWD.pfnDrawMD2 = hwSym("DrawMD2",NULL); + HWD.pfnDrawModel = hwSym("DrawModel",NULL); + HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); HWD.pfnSetTransform = hwSym("SetTransform",NULL); HWD.pfnGetRenderVersion = hwSym("GetRenderVersion",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 774ce5cb..177d6269 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -222,15 +222,6 @@ - - - - - - - - - @@ -384,16 +375,6 @@ - - - - - - - - - - @@ -494,4 +475,4 @@ - \ No newline at end of file + diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index d20dd672..40230912 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -87,30 +87,6 @@ Win32app - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - Hw_Hardware @@ -476,36 +452,6 @@ Win32app - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - Hw_Hardware @@ -881,4 +827,4 @@ A_Asm - \ No newline at end of file +