From 1ca28badad2f9a08713ce06100903acc1257d12c Mon Sep 17 00:00:00 2001 From: mittorn Date: Wed, 20 Mar 2019 04:29:25 +0700 Subject: [PATCH] ref_soft: initial 2D drawing implementation --- r_context.c | 814 ++++++++++++++++++++++++++++++++ r_draw.c | 283 +++++++++++ r_glblit.c | 110 +++++ r_image.c | 1308 +++++++++++++++++++++++++++++++++++++++++++++++++++ r_local.h | 710 ++++++++++++++++++++++++++++ r_triapi.c | 355 ++++++++++++++ r_vgui.c | 225 +++++++++ wscript | 55 +++ 8 files changed, 3860 insertions(+) create mode 100644 r_context.c create mode 100644 r_draw.c create mode 100644 r_glblit.c create mode 100644 r_image.c create mode 100644 r_local.h create mode 100644 r_triapi.c create mode 100644 r_vgui.c create mode 100644 wscript diff --git a/r_context.c b/r_context.c new file mode 100644 index 00000000..55e8ff12 --- /dev/null +++ b/r_context.c @@ -0,0 +1,814 @@ +/* +vid_sdl.c - SDL vid component +Copyright (C) 2018 a1batross + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "r_local.h" + +ref_api_t gEngfuncs; +ref_globals_t *gpGlobals; +ref_instance_t RI; +gl_globals_t tr; +ref_speeds_t r_stats; +byte *r_temppool; +cvar_t *gl_emboss_scale; +viddef_t vid; +static void R_ClearScreen( void ) +{ + +} + +static qboolean IsNormalPass( void ) +{ + return RP_NORMALPASS(); +} + +static void R_IncrementSpeedsCounter( int type ) +{ + switch( type ) + { + case RS_ACTIVE_TENTS: + r_stats.c_active_tents_count++; + break; + default: + gEngfuncs.Host_Error( "R_IncrementSpeedsCounter: unsupported type %d\n", type ); + } +} + +static const byte *R_GetTextureOriginalBuffer( unsigned int idx ) +{ + /*gl_texture_t *glt = R_GetTexture( idx ); + + if( !glt || !glt->original || !glt->original->buffer ) + return NULL;*/ + + return NULL; +} + +static int R_GetBuiltinTexture( enum ref_shared_texture_e type ) +{ + switch( type ) + { + case REF_DEFAULT_TEXTURE: return tr.defaultTexture; + case REF_GRAY_TEXTURE: return tr.grayTexture; + case REF_WHITE_TEXTURE: return tr.whiteTexture; + case REF_SOLIDSKY_TEXTURE: return tr.solidskyTexture; + case REF_ALPHASKY_TEXTURE: return tr.alphaskyTexture; + default: gEngfuncs.Host_Error( "R_GetBuiltinTexture: unsupported type %d\n", type ); + } + + return 0; +} + +static void R_FreeSharedTexture( enum ref_shared_texture_e type ) +{ + int num = 0; + + switch( type ) + { + case REF_SOLIDSKY_TEXTURE: + num = tr.solidskyTexture; + tr.solidskyTexture = 0; + break; + case REF_ALPHASKY_TEXTURE: + num = tr.alphaskyTexture; + tr.alphaskyTexture = 0; + break; + case REF_DEFAULT_TEXTURE: + case REF_GRAY_TEXTURE: + case REF_WHITE_TEXTURE: + gEngfuncs.Host_Error( "R_FreeSharedTexture: invalid type %d\n", type ); + default: gEngfuncs.Host_Error( "R_FreeSharedTexture: unsupported type %d\n", type ); + } + + GL_FreeTexture( num ); +} + +/* +============= +CL_FillRGBA + +============= +*/ +static void CL_FillRGBA( float _x, float _y, float _w, float _h, int r, int g, int b, int a ) +{ + +} + +/* +============= +pfnFillRGBABlend + +============= +*/ +static void GAME_EXPORT CL_FillRGBABlend( float _x, float _y, float _w, float _h, int r, int g, int b, int a ) +{ + +} + + +qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf ) +{ + qboolean loaded = true; + + if( create ) + { + + + switch( mod->type ) + { + case mod_studio: + // Mod_LoadStudioModel( mod, buf, loaded ); + break; + case mod_sprite: + //Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo ); + break; + case mod_alias: + //Mod_LoadAliasModel( mod, buf, &loaded ); + break; + case mod_brush: + // Mod_LoadBrushModel( mod, buf, loaded ); + break; + + default: gEngfuncs.Host_Error( "Mod_LoadModel: unsupported type %d\n", mod->type ); + } + } + + if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData ) + gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf ); + + //if( !create ) + //Mod_UnloadTextures( mod ); + + return loaded; +} + +static int GL_RenderGetParm( int parm, int arg ) +{ + image_t *glt; + + switch( parm ) + { + case PARM_TEX_WIDTH: + glt = R_GetTexture( arg ); + return glt->width; + case PARM_TEX_HEIGHT: + glt = R_GetTexture( arg ); + return glt->height; + case PARM_TEX_SRC_WIDTH: + glt = R_GetTexture( arg ); + return glt->srcWidth; + case PARM_TEX_SRC_HEIGHT: + glt = R_GetTexture( arg ); + return glt->srcHeight; + case PARM_TEX_MIPCOUNT: + glt = R_GetTexture( arg ); + return glt->numMips; + case PARM_TEX_DEPTH: + glt = R_GetTexture( arg ); + return glt->depth; + case PARM_TEX_SKYBOX: + Assert( arg >= 0 && arg < 6 ); + return tr.skyboxTextures[arg]; + case PARM_TEX_SKYTEXNUM: + return tr.skytexturenum; + case PARM_TEX_LIGHTMAP: + arg = bound( 0, arg, MAX_LIGHTMAPS - 1 ); + return tr.lightmapTextures[arg]; + case PARM_WIDESCREEN: + return gpGlobals->wideScreen; + case PARM_FULLSCREEN: + return gpGlobals->fullScreen; + case PARM_SCREEN_WIDTH: + return gpGlobals->width; + case PARM_SCREEN_HEIGHT: + return gpGlobals->height; + case PARM_TEX_FLAGS: + glt = R_GetTexture( arg ); + return glt->flags; + case PARM_LIGHTSTYLEVALUE: + arg = bound( 0, arg, MAX_LIGHTSTYLES - 1 ); + return tr.lightstylevalue[arg]; + case PARM_MAX_IMAGE_UNITS: + return 1; + case PARM_REBUILD_GAMMA: + return 0;//glConfig.softwareGammaUpdate; + case PARM_SURF_SAMPLESIZE: + if( arg >= 0 && arg < WORLDMODEL->numsurfaces ) + return gEngfuncs.Mod_SampleSizeForFace( &WORLDMODEL->surfaces[arg] ); + return LM_SAMPLE_SIZE; + case PARM_SKY_SPHERE: + return gEngfuncs.CL_GetRenderParm( parm, arg ) && !tr.fCustomSkybox; + default: + return gEngfuncs.CL_GetRenderParm( parm, arg ); + } + return 0; +} + +static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale ) +{ + image_t *glt = R_GetTexture( texture ); + + if( xScale ) *xScale = glt->xscale; + if( yScale ) *yScale = glt->yscale; +} + +static void R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density ) +{ + image_t *glt = R_GetTexture( texture ); + + if( red ) *red = glt->fogParams[0]; + if( green ) *green = glt->fogParams[1]; + if( blue ) *blue = glt->fogParams[2]; + if( density ) *density = glt->fogParams[3]; +} + + +static void R_SetCurrentEntity( cl_entity_t *ent ) +{ + RI.currententity = ent; + + // set model also + if( RI.currententity != NULL ) + { + RI.currentmodel = RI.currententity->model; + } +} + +static void R_SetCurrentModel( model_t *mod ) +{ + RI.currentmodel = mod; +} + +static float R_GetFrameTime( void ) +{ + return tr.frametime; +} + +static const char *GL_TextureName( unsigned int texnum ) +{ + return "";//return R_GetTexture( texnum )->name; +} + +const byte *GL_TextureData( unsigned int texnum ) +{ +// rgbdata_t *pic = R_GetTexture( texnum )->original; + + //if( pic != NULL ) + //return pic->buffer; + return NULL; +} + +void Mod_BrushUnloadTextures( model_t *mod ) +{ + int i; + + for( i = 0; i < mod->numtextures; i++ ) + { + texture_t *tx = mod->textures[i]; + if( !tx || tx->gl_texturenum == tr.defaultTexture ) + continue; // free slot + + //GL_FreeTexture( tx->gl_texturenum ); // main texture + //GL_FreeTexture( tx->fb_texturenum ); // luma texture + } +} + +void Mod_UnloadTextures( model_t *mod ) +{ + int i, j; + + Assert( mod != NULL ); + + switch( mod->type ) + { + case mod_studio: + //Mod_StudioUnloadTextures( mod->cache.data ); + break; + case mod_alias: + //Mod_AliasUnloadTextures( mod->cache.data ); + break; + case mod_brush: + Mod_BrushUnloadTextures( mod ); + break; + case mod_sprite: + //Mod_SpriteUnloadTextures( mod->cache.data ); + break; + default: gEngfuncs.Host_Error( "Mod_UnloadModel: unsupported type %d\n", mod->type ); + } +} + +void R_ProcessEntData( qboolean allocate ) +{ + +} + +// stubs + +void GL_SetTexCoordArrayMode() +{ + +} +void R_InitBlit(); +void GL_OnContextCreated() +{ + R_InitBlit(); + +} + +void GL_InitExtensions() +{ + +} +void GL_ClearExtensions() +{ + +} +void R_BeginFrame(qboolean clearScene) +{ +} + +void R_RenderScene() +{ + +} + +void R_EndFrame() +{ + // blit pixels with GL until engine supports REF_SOFT context + R_BlitScreen(); +} + +void R_PushScene() +{ + +} + +void R_PopScene() +{ + +} + +void GL_BackendStartFrame() +{ + +} + +void GL_BackendEndFrame() +{ + +} + +void R_AllowFog(qboolean allowed) +{ + +} + +void GL_SetRenderMode(int mode) +{ + /// TODO: table shading/blending??? + /// maybe, setup block drawing function pointers here +} + +qboolean R_AddEntity(struct cl_entity_s *pRefEntity, int entityType) +{ + // no entities support until we draw world... + return false; +} + +void CL_AddCustomBeam(cl_entity_t *pEnvBeam) +{ + // same for beams +} + +void R_ShowTextures() +{ + // textures undone too +} + +void R_ShowTree() +{ + // do we really need this here??? +} + +void R_SetupSky(const char *skyboxname) +{ + +} + +qboolean VID_ScreenShot(const char *filename, int shot_type) +{ + +} + +qboolean VID_CubemapShot(const char *base, uint size, const float *vieworg, qboolean skyshot) +{ + // cubemaps? in my softrender??? +} + +colorVec R_LightPoint(const vec3_t p0) +{ + colorVec c = {0}; + return c; +} + +void R_DecalShoot(int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale) +{ + +} + +void R_DecalRemoveAll(int texture) +{ + +} + +int R_CreateDecalList(decallist_t *pList) +{ + return 0; +} + +void R_ClearAllDecals() +{ + +} + +float R_StudioEstimateFrame(cl_entity_t *e, mstudioseqdesc_t *pseqdesc) +{ + return 0; +} + +void R_StudioLerpMovement(cl_entity_t *e, double time, vec3_t origin, vec3_t angles) +{ + +} + +void CL_InitStudioAPI() +{ + +} + +void R_InitSkyClouds(mip_t *mt, texture_t *tx, qboolean custom_palette) +{ + +} + +void GL_SubdivideSurface(msurface_t *fa) +{ + +} + +void CL_RunLightStyles() +{ + +} + +void Mod_LoadMapSprite(model_t *mod, const void *buffer, size_t size, qboolean *loaded) +{ + +} + +void Mod_StudioLoadTextures(model_t *mod, void *data) +{ + +} + +void CL_DrawParticles(double frametime, particle_t *cl_active_particles, float partsize) +{ + +} + +void CL_DrawBeams(int fTrans, BEAM *active_beams) +{ + +} + +void CL_DrawTracers(double frametime, particle_t *cl_active_tracers) +{ + +} + +qboolean R_BeamCull(const vec3_t start, const vec3_t end, qboolean pvsOnly) +{ + return false; +} + +void DrawSingleDecal(decal_t *pDecal, msurface_t *fa) +{ + +} + +float *R_DecalSetupVerts(decal_t *pDecal, msurface_t *surf, int texture, int *outCount) +{ + return NULL; +} + +void R_EntityRemoveDecals(model_t *mod) +{ + +} + +void GL_SelectTexture(int texture) +{ + +} + +void GL_LoadTexMatrixExt(const float *glmatrix) +{ + +} + +void GL_LoadIdentityTexMatrix() +{ + +} + +void GL_CleanUpTextureUnits(int last) +{ + +} + +void GL_TexGen(unsigned int coord, unsigned int mode) +{ + +} + +void GL_TextureTarget(uint target) +{ + +} + +void CL_DrawParticlesExternal(const ref_viewpass_t *rvp, qboolean trans_pass, float frametime) +{ + // no renderapi support +} + +struct mstudiotex_s *R_StudioGetTexture(cl_entity_t *e) +{ + return NULL; +} + +colorVec R_LightVec(const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec) +{ + colorVec v = {0}; + return v; +} + +int R_RenderFrame(const struct ref_viewpass_s *vp) +{ + +} + +void GL_BuildLightmaps() +{ + +} + +void Mod_SetOrthoBounds(const float *mins, const float *maxs) +{ + +} + +qboolean R_SpeedsMessage(char *out, size_t size) +{ + return false; +} + +byte *Mod_GetCurrentVis() +{ + return NULL; +} + +void R_ClearScene() +{ + +} + +void R_NewMap() +{ + +} + +void R_ScreenToWorld(const vec3_t screen, vec3_t point) +{ + +} +void GL_SetupAttributes( int safegl ) +{ + gEngfuncs.Con_Reportf( "Creating an extended GL context for debug...\n" ); + gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_FLAGS, REF_GL_CONTEXT_DEBUG_FLAG ); + + // untill we have any blitter in ref api, setup GL + gEngfuncs.GL_SetAttribute( REF_GL_CONTEXT_PROFILE_MASK, REF_GL_CONTEXT_PROFILE_COMPATIBILITY ); + gEngfuncs.GL_SetAttribute( REF_GL_DOUBLEBUFFER, 1 ); + + gEngfuncs.GL_SetAttribute( REF_GL_RED_SIZE, 5 ); + gEngfuncs.GL_SetAttribute( REF_GL_GREEN_SIZE, 6 ); + gEngfuncs.GL_SetAttribute( REF_GL_BLUE_SIZE, 5 ); +} + + + + +qboolean R_Init() +{ + gl_emboss_scale = gEngfuncs.Cvar_Get( "gl_emboss_scale", "0", FCVAR_ARCHIVE|FCVAR_LATCH, "fake bumpmapping scale" ); + // create the window and set up the context + if( !gEngfuncs.R_Init_Video( REF_GL )) // request GL context + { + gEngfuncs.R_Free_Video(); + + gEngfuncs.Host_Error( "Can't initialize video subsystem\nProbably driver was not installed" ); + return false; + } + r_temppool = Mem_AllocPool( "ref_sw zone" ); + vid.width = 1920; + vid.height = 1080; + vid.rowbytes = 1920; // rowpixels + + vid.buffer = Mem_Malloc( r_temppool, 1920*1080*sizeof( pixel_t ) ); + + R_InitImages(); + return true; +} + +void R_Shutdown() +{ + R_ShutdownImages(); + gEngfuncs.R_Free_Video(); +} + +ref_interface_t gReffuncs = +{ + R_Init, + R_Shutdown, + + GL_SetupAttributes, + GL_OnContextCreated, + GL_InitExtensions, + GL_ClearExtensions, + + R_BeginFrame, + R_RenderScene, + R_EndFrame, + R_PushScene, + R_PopScene, + GL_BackendStartFrame, + GL_BackendEndFrame, + + R_ClearScreen, + R_AllowFog, + GL_SetRenderMode, + + R_AddEntity, + CL_AddCustomBeam, + R_ProcessEntData, + + IsNormalPass, + + R_ShowTextures, + R_ShowTree, + R_IncrementSpeedsCounter, + + R_GetTextureOriginalBuffer, + GL_LoadTextureFromBuffer, + R_GetBuiltinTexture, + R_FreeSharedTexture, + GL_ProcessTexture, + R_SetupSky, + + R_Set2DMode, + R_DrawStretchRaw, + R_DrawStretchPic, + R_DrawTileClear, + CL_FillRGBA, + CL_FillRGBABlend, + + VID_ScreenShot, + VID_CubemapShot, + + R_LightPoint, + + R_DecalShoot, + R_DecalRemoveAll, + R_CreateDecalList, + R_ClearAllDecals, + + R_StudioEstimateFrame, + R_StudioLerpMovement, + CL_InitStudioAPI, + + R_InitSkyClouds, + GL_SubdivideSurface, + CL_RunLightStyles, + + R_GetSpriteParms, + R_GetSpriteTexture, + + Mod_LoadMapSprite, + Mod_ProcessRenderData, + Mod_StudioLoadTextures, + + CL_DrawParticles, + CL_DrawTracers, + CL_DrawBeams, + R_BeamCull, + + GL_RenderGetParm, + R_GetDetailScaleForTexture, + R_GetExtraParmsForTexture, + R_GetFrameTime, + + R_SetCurrentEntity, + R_SetCurrentModel, + + GL_FindTexture, + GL_TextureName, + GL_TextureData, + GL_LoadTexture, + GL_CreateTexture, + GL_LoadTextureArray, + GL_CreateTextureArray, + GL_FreeTexture, + + DrawSingleDecal, + R_DecalSetupVerts, + R_EntityRemoveDecals, + + R_UploadStretchRaw, + + GL_Bind, + GL_SelectTexture, + GL_LoadTexMatrixExt, + GL_LoadIdentityTexMatrix, + GL_CleanUpTextureUnits, + GL_TexGen, + GL_TextureTarget, + GL_SetTexCoordArrayMode, + GL_UpdateTexSize, + NULL, + NULL, + + CL_DrawParticlesExternal, + R_LightVec, + R_StudioGetTexture, + + R_RenderFrame, + GL_BuildLightmaps, + Mod_SetOrthoBounds, + R_SpeedsMessage, + Mod_GetCurrentVis, + R_NewMap, + R_ClearScene, + + TriRenderMode, + TriBegin, + TriEnd, + _TriColor4f, + TriColor4ub, + TriTexCoord2f, + TriVertex3fv, + TriVertex3f, + TriWorldToScreen, + TriFog, + R_ScreenToWorld, + TriGetMatrix, + TriFogParams, + TriCullFace, + + VGUI_DrawInit, + VGUI_DrawShutdown, + VGUI_SetupDrawingText, + VGUI_SetupDrawingRect, + VGUI_SetupDrawingImage, + VGUI_BindTexture, + VGUI_EnableTexture, + VGUI_CreateTexture, + VGUI_UploadTexture, + VGUI_UploadTextureBlock, + VGUI_DrawQuad, + VGUI_GetTextureSizes, + VGUI_GenerateTexture, +}; + +int GAME_EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals ) +{ + if( version != REF_API_VERSION ) + return 0; + + // fill in our callbacks + memcpy( funcs, &gReffuncs, sizeof( ref_interface_t )); + memcpy( &gEngfuncs, engfuncs, sizeof( ref_api_t )); + gpGlobals = globals; + + return REF_API_VERSION; +} diff --git a/r_draw.c b/r_draw.c new file mode 100644 index 00000000..aa9c8ba7 --- /dev/null +++ b/r_draw.c @@ -0,0 +1,283 @@ +/* +gl_draw.c - orthogonal drawing stuff +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "r_local.h" + +/* +============= +R_GetImageParms +============= +*/ +void R_GetTextureParms( int *w, int *h, int texnum ) +{ + image_t *glt; + + glt = R_GetTexture( texnum ); + if( w ) *w = glt->srcWidth; + if( h ) *h = glt->srcHeight; +} + +/* +============= +R_GetSpriteParms + +same as GetImageParms but used +for sprite models +============= +*/ +void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite ) +{ + mspriteframe_t *pFrame; + + if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ? + //pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f ); + + //if( frameWidth ) *frameWidth = pFrame->width; +// if( frameHeight ) *frameHeight = pFrame->height; + //if( numFrames ) *numFrames = pSprite->numframes; +} + +int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame ) +{ + if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data ) + return 0; + + return 0;//R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum; +} + + +/* +============= +Draw_StretchPicImplementation +============= +*/ +void R_DrawStretchPicImplementation (int x, int y, int w, int h, int s1, int t1, int s2, int t2, image_t *pic) +{ + pixel_t *dest, *source; + unsigned int v, u, sv; + unsigned int height; + unsigned int f, fstep; + int skip; + + if( x < 0 ) + { + s1 += (-x)*(s2-s1) / w; + x = 0; + } + if( x + w > vid.width ) + { + s2 -= (x + w - vid.width) * (s2 - s1)/ w ; + w = vid.width - x; + } + if( y + h > vid.height ) + { + t2 -= (y + h - vid.height) * (t2 - t1) / h; + h = vid.height - y; + } + + if( !pic->pixels[0] || s1 >= s2 || t1 >= t2 ) + return; + + //gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] ); + + height = h; + if (y < 0) + { + skip = -y; + height += y; + y = 0; + } + else + skip = 0; + + dest = vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vpixels[0] + sv*pic->width + s1; + if (w == s2 - s1) + memcpy (dest, source, w * 2); + else + { + f = 0; + fstep = s2*0x10000/w; + for (u=0 ; u>16]; + f += fstep; + dest[u+1] = source[f>>16]; + f += fstep; + dest[u+2] = source[f>>16]; + f += fstep; + dest[u+3] = source[f>>16]; + f += fstep; + } + } + } +} + + +/* +============= +R_DrawStretchPic +============= +*/ +void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum ) +{ + image_t *pic = R_GetTexture(texnum); +// GL_Bind( XASH_TEXTURE0, texnum ); + if( s2 > 1 || t2 > 2 ) + return; + if( w <= 0 || h <= 0 ) + return; + R_DrawStretchPicImplementation(x,y,w,h, pic->width * s1, pic->height * t1, pic->width * s2, pic->height * t2, pic); +} + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void R_DrawTileClear( int texnum, int x, int y, int w, int h ) +{ + int tw, th, x2, i, j; + image_t *pic; + pixel_t *psrc, *pdest; + + //GL_SetRenderMode( kRenderNormal ); + _TriColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + GL_Bind( XASH_TEXTURE0, texnum ); + + pic = R_GetTexture( texnum ); + + tw = pic->width; + th = pic->height; + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if (x + w > vid.width) + w = vid.width - x; + if (y + h > vid.height) + h = vid.height - y; + if (w <= 0 || h <= 0) + return; + + x2 = x + w; + pdest = vid.buffer + y*vid.rowbytes; + for (i=0 ; ipixels[0] + tw * ((i+y)&63); + for (j=x ; jwidth = cols; + tex->height = rows; +} + +/* +=============== +R_Set2DMode +=============== +*/ +void R_Set2DMode( qboolean enable ) +{ + if( enable ) + { +// if( glState.in2DMode ) + // return; +#if 0 + // set 2D virtual screen size + pglViewport( 0, 0, gpGlobals->width, gpGlobals->height ); + pglMatrixMode( GL_PROJECTION ); + pglLoadIdentity(); + pglOrtho( 0, gpGlobals->width, gpGlobals->height, 0, -99999, 99999 ); + pglMatrixMode( GL_MODELVIEW ); + pglLoadIdentity(); + + GL_Cull( GL_NONE ); + + pglDepthMask( GL_FALSE ); + pglDisable( GL_DEPTH_TEST ); + pglEnable( GL_ALPHA_TEST ); + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); +#endif + + // glState.in2DMode = true; + RI.currententity = NULL; + RI.currentmodel = NULL; + } + else + { +#if 0 + pglDepthMask( GL_TRUE ); + pglEnable( GL_DEPTH_TEST ); + glState.in2DMode = false; + + pglMatrixMode( GL_PROJECTION ); + GL_LoadMatrix( RI.projectionMatrix ); + + pglMatrixMode( GL_MODELVIEW ); + GL_LoadMatrix( RI.worldviewMatrix ); + + GL_Cull( GL_FRONT ); +#endif + } +} diff --git a/r_glblit.c b/r_glblit.c new file mode 100644 index 00000000..9e8214d1 --- /dev/null +++ b/r_glblit.c @@ -0,0 +1,110 @@ +#include "r_local.h" +#include "../ref_gl/gl_export.h" + + +/* +======================== +DebugCallback + +For ARB_debug_output +======================== +*/ +static void APIENTRY GL_DebugOutput( GLuint source, GLuint type, GLuint id, GLuint severity, GLint length, const GLcharARB *message, GLvoid *userParam ) +{ + switch( type ) + { + case GL_DEBUG_TYPE_ERROR_ARB: + gEngfuncs.Con_Printf( S_OPENGL_ERROR "%s\n", message ); + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + gEngfuncs.Con_Printf( S_OPENGL_WARN "%s\n", message ); + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + gEngfuncs.Con_Printf( S_OPENGL_WARN "%s\n", message ); + break; + case GL_DEBUG_TYPE_PORTABILITY_ARB: + gEngfuncs.Con_Reportf( S_OPENGL_WARN "%s\n", message ); + break; + case GL_DEBUG_TYPE_PERFORMANCE_ARB: + gEngfuncs.Con_Printf( S_OPENGL_NOTE "%s\n", message ); + break; + case GL_DEBUG_TYPE_OTHER_ARB: + default: + gEngfuncs.Con_Printf( S_OPENGL_NOTE "%s\n", message ); + break; + } +} +int tex; + +#define LOAD(x) p##x = gEngfuncs.GL_GetProcAddress(#x) +void R_InitBlit() +{ + LOAD(glBegin); + LOAD(glEnd); + LOAD(glTexCoord2f); + LOAD(glVertex2f); + LOAD(glEnable); + LOAD(glDisable); + LOAD(glTexImage2D); + LOAD(glOrtho); + LOAD(glMatrixMode); + LOAD(glLoadIdentity); + LOAD(glViewport); + LOAD(glBindTexture); + LOAD(glDebugMessageCallbackARB); + LOAD(glDebugMessageControlARB); + LOAD(glGetError); + LOAD(glGenTextures); + LOAD(glTexParameteri); + + if( gpGlobals->developer ) + { + gEngfuncs.Con_Reportf( "Installing GL_DebugOutput...\n"); + pglDebugMessageCallbackARB( GL_DebugOutput, NULL ); + + // force everything to happen in the main thread instead of in a separate driver thread + pglEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ); + } + + // enable all the low priority messages + pglDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, true ); + pglGenTextures( 1, &tex ); +} + + +void R_BlitScreen() +{ + //memset( vid.buffer, 10, vid.width * vid.height ); + pglBindTexture(GL_TEXTURE_2D, tex); + pglViewport( 0, 0, gpGlobals->width, gpGlobals->height ); + pglMatrixMode( GL_PROJECTION ); + pglLoadIdentity(); + pglOrtho( 0, gpGlobals->width, gpGlobals->height, 0, -99999, 99999 ); + pglMatrixMode( GL_MODELVIEW ); + pglLoadIdentity(); + + pglEnable( GL_TEXTURE_2D ); + pglBindTexture(GL_TEXTURE_2D, tex); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + //gEngfuncs.Con_Printf("%d\n",pglGetError()); + pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vid.width, vid.height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, vid.buffer ); + //gEngfuncs.Con_Printf("%d\n",pglGetError()); + pglBegin( GL_QUADS ); + pglTexCoord2f( 0, 0 ); + pglVertex2f( 0, 0 ); + + pglTexCoord2f( 1, 0 ); + pglVertex2f( vid.width, 0 ); + + pglTexCoord2f( 1, 1 ); + pglVertex2f( vid.width, vid.height ); + + pglTexCoord2f( 0, 1 ); + pglVertex2f( 0, vid.height ); + pglEnd(); + pglDisable( GL_TEXTURE_2D ); + gEngfuncs.GL_SwapBuffers(); +} diff --git a/r_image.c b/r_image.c new file mode 100644 index 00000000..166060bc --- /dev/null +++ b/r_image.c @@ -0,0 +1,1308 @@ +/* +gl_image.c - texture uploading and processing +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "r_local.h" + +#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2) + +static image_t r_images[MAX_TEXTURES]; +static image_t* r_imagesHashTable[TEXTURES_HASH_SIZE]; +static uint r_numImages; + +#define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE )) +/* +================= +R_GetTexture + +acess to array elem +================= +*/ +image_t *R_GetTexture( unsigned int texnum ) +{ + ASSERT( texnum >= 0 && texnum < MAX_TEXTURES ); + return &r_images[texnum]; +} + +/* +================= +GL_Bind +================= +*/ +void GL_Bind( int tmu, unsigned int texnum ) +{ + image_t *texture; + + texture = &r_images[texnum]; +} + +/* +================= +GL_ApplyTextureParams +================= +*/ +void GL_ApplyTextureParams( image_t *tex ) +{ + + Assert( tex != NULL ); +} + +/* +================= +GL_UpdateTextureParams +================= +*/ +static void GL_UpdateTextureParams( int iTexture ) +{ + image_t *tex = &r_images[iTexture]; + + Assert( tex != NULL ); + + if( !tex->pixels) return; // free slot + + GL_Bind( XASH_TEXTURE0, iTexture ); +} + +/* +================= +R_SetTextureParameters +================= +*/ +void R_SetTextureParameters( void ) +{ + int i; + + // change all the existing mipmapped texture objects + for( i = 0; i < r_numImages; i++ ) + GL_UpdateTextureParams( i ); +} + + +/* +================== +GL_CalcImageSize +================== +*/ +static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int depth ) +{ + size_t size = 0; + + // check the depth error + depth = Q_max( 1, depth ); + + switch( format ) + { + case PF_RGB_24: + case PF_BGR_24: + size = width * height * depth * 3; + break; + case PF_BGRA_32: + case PF_RGBA_32: + size = width * height * depth * 4; + break; + case PF_DXT1: + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth; + break; + case PF_DXT3: + case PF_DXT5: + case PF_ATI2: + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth; + break; + } + + return size; +} + +/* +================== +GL_CalcTextureSize +================== +*/ +static size_t GL_CalcTextureSize( int width, int height, int depth ) +{ + return width * height * 2; +} + +static int GL_CalcMipmapCount( image_t *tex, qboolean haveBuffer ) +{ + int width, height; + int mipcount; + + Assert( tex != NULL ); + + if( !haveBuffer ) + return 1; + + // generate mip-levels by user request + if( FBitSet( tex->flags, TF_NOMIPMAP )) + return 1; + + // mip-maps can't exceeds 4 + for( mipcount = 0; mipcount < 4; mipcount++ ) + { + width = Q_max( 1, ( tex->width >> mipcount )); + height = Q_max( 1, ( tex->height >> mipcount )); + if( width == 1 && height == 1 ) + break; + } + + return mipcount + 1; +} + +/* +================ +GL_SetTextureDimensions +================ +*/ +static void GL_SetTextureDimensions( image_t *tex, int width, int height, int depth ) +{ + int maxTextureSize = 1024; + int maxDepthSize = 1; + + Assert( tex != NULL ); + + // store original sizes + tex->srcWidth = width; + tex->srcHeight = height; + + if( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize ) + { + while( width > maxTextureSize || height > maxTextureSize ) + { + width >>= 1; + height >>= 1; + } + } + + // set the texture dimensions + tex->width = Q_max( 1, width ); + tex->height = Q_max( 1, height ); + tex->depth = Q_max( 1, depth ); +} + +/* +=============== +GL_SetTextureTarget +=============== +*/ +static void GL_SetTextureTarget( image_t *tex, rgbdata_t *pic ) +{ + Assert( pic != NULL ); + Assert( tex != NULL ); + + // correct depth size + pic->depth = Q_max( 1, pic->depth ); + tex->numMips = 0; // begin counting + + // correct mip count + pic->numMips = Q_max( 1, pic->numMips ); +} + +/* +=============== +GL_SetTextureFormat +=============== +*/ +static void GL_SetTextureFormat( image_t *tex, pixformat_t format, int channelMask ) +{ + qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR ); + qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA ); + + Assert( tex != NULL ); + tex->transparent = !!( channelMask & IMAGE_HAS_ALPHA ); +} + +/* +================= +GL_ResampleTexture + +Assume input buffer is RGBA +================= +*/ +byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int outWidth, int outHeight, qboolean isNormalMap ) +{ + uint frac, fracStep; + uint *in = (uint *)source; + uint p1[0x1000], p2[0x1000]; + byte *pix1, *pix2, *pix3, *pix4; + uint *out, *inRow1, *inRow2; + static byte *scaledImage = NULL; // pointer to a scaled image + vec3_t normal; + int i, x, y; + + if( !source ) return NULL; + + scaledImage = Mem_Realloc( r_temppool, scaledImage, outWidth * outHeight * 4 ); + fracStep = inWidth * 0x10000 / outWidth; + out = (uint *)scaledImage; + + frac = fracStep >> 2; + for( i = 0; i < outWidth; i++ ) + { + p1[i] = 4 * (frac >> 16); + frac += fracStep; + } + + frac = (fracStep >> 2) * 3; + for( i = 0; i < outWidth; i++ ) + { + p2[i] = 4 * (frac >> 16); + frac += fracStep; + } + + if( isNormalMap ) + { + for( y = 0; y < outHeight; y++, out += outWidth ) + { + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight); + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight); + + for( x = 0; x < outWidth; x++ ) + { + pix1 = (byte *)inRow1 + p1[x]; + pix2 = (byte *)inRow1 + p2[x]; + pix3 = (byte *)inRow2 + p1[x]; + pix4 = (byte *)inRow2 + p2[x]; + + normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] ); + normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] ); + normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] ); + + if( !VectorNormalizeLength( normal )) + VectorSet( normal, 0.5f, 0.5f, 1.0f ); + + ((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]); + ((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]); + ((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]); + ((byte *)(out+x))[3] = 255; + } + } + } + else + { + for( y = 0; y < outHeight; y++, out += outWidth ) + { + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight); + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight); + + for( x = 0; x < outWidth; x++ ) + { + pix1 = (byte *)inRow1 + p1[x]; + pix2 = (byte *)inRow1 + p2[x]; + pix3 = (byte *)inRow2 + p1[x]; + pix4 = (byte *)inRow2 + p2[x]; + + ((byte *)(out+x))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2; + ((byte *)(out+x))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2; + ((byte *)(out+x))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2; + ((byte *)(out+x))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2; + } + } + } + + return scaledImage; +} + +/* +================= +GL_BoxFilter3x3 + +box filter 3x3 +================= +*/ +void GL_BoxFilter3x3( byte *out, const byte *in, int w, int h, int x, int y ) +{ + int r = 0, g = 0, b = 0, a = 0; + int count = 0, acount = 0; + int i, j, u, v; + const byte *pixel; + + for( i = 0; i < 3; i++ ) + { + u = ( i - 1 ) + x; + + for( j = 0; j < 3; j++ ) + { + v = ( j - 1 ) + y; + + if( u >= 0 && u < w && v >= 0 && v < h ) + { + pixel = &in[( u + v * w ) * 4]; + + if( pixel[3] != 0 ) + { + r += pixel[0]; + g += pixel[1]; + b += pixel[2]; + a += pixel[3]; + acount++; + } + } + } + } + + if( acount == 0 ) + acount = 1; + + out[0] = r / acount; + out[1] = g / acount; + out[2] = b / acount; +// out[3] = (int)( SimpleSpline( ( a / 12.0f ) / 255.0f ) * 255 ); +} + +/* +================= +GL_ApplyFilter + +Apply box-filter to 1-bit alpha +================= +*/ +byte *GL_ApplyFilter( const byte *source, int width, int height ) +{ + byte *in = (byte *)source; + byte *out = (byte *)source; + int i; + + if( gEngfuncs.Host_IsQuakeCompatible() ) + return in; + + for( i = 0; source && i < width * height; i++, in += 4 ) + { + if( in[0] == 0 && in[1] == 0 && in[2] == 0 && in[3] == 0 ) + GL_BoxFilter3x3( in, source, width, height, i % width, i / width ); + } + + return out; +} + +/* +================= +GL_BuildMipMap + +Operates in place, quartering the size of the texture +================= +*/ +static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, int flags ) +{ + byte *out = in; + int instride = ALIGN( srcWidth * 4, 1 ); + int mipWidth, mipHeight, outpadding; + int row, x, y, z; + vec3_t normal; + + if( !in ) return; + + mipWidth = Q_max( 1, ( srcWidth >> 1 )); + mipHeight = Q_max( 1, ( srcHeight >> 1 )); + outpadding = ALIGN( mipWidth * 4, 1 ) - mipWidth * 4; + row = srcWidth << 2; + + if( FBitSet( flags, TF_ALPHACONTRAST )) + { + memset( in, mipWidth, mipWidth * mipHeight * 4 ); + return; + } + + // move through all layers + for( z = 0; z < srcDepth; z++ ) + { + if( FBitSet( flags, TF_NORMALMAP )) + { + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding ) + { + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in; + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 ) + { + if((( x << 1 ) + 1 ) < srcWidth ) + { + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( in[row+4] ) + + MAKE_SIGNED( next[row+0] ) + MAKE_SIGNED( next[row+4] ); + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( in[row+5] ) + + MAKE_SIGNED( next[row+1] ) + MAKE_SIGNED( next[row+5] ); + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( in[row+6] ) + + MAKE_SIGNED( next[row+2] ) + MAKE_SIGNED( next[row+6] ); + } + else + { + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( next[row+0] ); + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( next[row+1] ); + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( next[row+2] ); + } + + if( !VectorNormalizeLength( normal )) + VectorSet( normal, 0.5f, 0.5f, 1.0f ); + + out[0] = 128 + (byte)(127.0f * normal[0]); + out[1] = 128 + (byte)(127.0f * normal[1]); + out[2] = 128 + (byte)(127.0f * normal[2]); + out[3] = 255; + } + } + } + else + { + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding ) + { + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in; + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 ) + { + if((( x << 1 ) + 1 ) < srcWidth ) + { + out[0] = (in[row+0] + in[row+4] + next[row+0] + next[row+4]) >> 2; + out[1] = (in[row+1] + in[row+5] + next[row+1] + next[row+5]) >> 2; + out[2] = (in[row+2] + in[row+6] + next[row+2] + next[row+6]) >> 2; + out[3] = (in[row+3] + in[row+7] + next[row+3] + next[row+7]) >> 2; + } + else + { + out[0] = (in[row+0] + next[row+0]) >> 1; + out[1] = (in[row+1] + next[row+1]) >> 1; + out[2] = (in[row+2] + next[row+2]) >> 1; + out[3] = (in[row+3] + next[row+3]) >> 1; + } + } + } + } + } +} + +/* +=============== +GL_UploadTexture + +upload texture into video memory +=============== +*/ +static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) +{ + byte *buf, *data; + size_t texsize, size; + uint width, height; + uint i, j, numSides; + uint offset = 0; + qboolean normalMap; + const byte *bufend; + + tex->fogParams[0] = pic->fogParams[0]; + tex->fogParams[1] = pic->fogParams[1]; + tex->fogParams[2] = pic->fogParams[2]; + tex->fogParams[3] = pic->fogParams[3]; + GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth ); + GL_SetTextureFormat( tex, pic->type, pic->flags ); + + gEngfuncs.Con_Printf("%s %d %d\n", tex->name, tex->width, tex->height ); + + if( !pic->buffer ) + return true; + + tex->pixels[0] = Mem_Calloc( r_temppool, tex->width * tex->height * sizeof(pixel_t) + 64 ); + for( i = 0; i < tex->width * tex->height; i++ ) + { + unsigned int r, g, b; + r = pic->buffer[i * 4 + 0] * BIT(5) / 256; + g = pic->buffer[i * 4 + 1] * BIT(6) / 256; + b = pic->buffer[i * 4 + 2] * BIT(5) / 256; + + /// TODO: use internal rgb565-based palette for textures and screen + tex->pixels[0][i] = r << (6 + 5) | (g << 5) | b; + } + +#if 0 + Assert( pic != NULL ); + Assert( tex != NULL ); + + GL_SetTextureTarget( tex, pic ); // must be first + + // make sure what target is correct + if( tex->target == GL_NONE ) + { + gEngfuncs.Con_DPrintf( S_ERROR "GL_UploadTexture: %s is not supported by your hardware\n", tex->name ); + return false; + } + + GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth ); + GL_SetTextureFormat( tex, pic->type, pic->flags ); + + tex->fogParams[0] = pic->fogParams[0]; + tex->fogParams[1] = pic->fogParams[1]; + tex->fogParams[2] = pic->fogParams[2]; + tex->fogParams[3] = pic->fogParams[3]; + + if(( pic->width * pic->height ) & 3 ) + { + // will be resampled, just tell me for debug targets + gEngfuncs.Con_Reportf( "GL_UploadTexture: %s s&3 [%d x %d]\n", tex->name, pic->width, pic->height ); + } + + buf = pic->buffer; + bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps + offset = GL_CalcImageSize( pic->type, pic->width, pic->height, pic->depth ); + texsize = GL_CalcTextureSize( tex->format, tex->width, tex->height, tex->depth ); + normalMap = FBitSet( tex->flags, TF_NORMALMAP ) ? true : false; + numSides = FBitSet( pic->flags, IMAGE_CUBEMAP ) ? 6 : 1; + + // uploading texture into video memory, change the binding + glState.currentTextures[glState.activeTMU] = tex->texnum; + pglBindTexture( tex->target, tex->texnum ); + + for( i = 0; i < numSides; i++ ) + { + // track the buffer bounds + if( buf != NULL && buf >= bufend ) + gEngfuncs.Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name ); + + if( ImageDXT( pic->type )) + { + for( j = 0; j < Q_max( 1, pic->numMips ); j++ ) + { + width = Q_max( 1, ( tex->width >> j )); + height = Q_max( 1, ( tex->height >> j )); + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); + size = GL_CalcImageSize( pic->type, width, height, tex->depth ); + GL_TextureImageDXT( tex, i, j, width, height, tex->depth, size, buf ); + tex->size += texsize; + buf += size; // move pointer + tex->numMips++; + + GL_CheckTexImageError( tex ); + } + } + else if( Q_max( 1, pic->numMips ) > 1 ) // not-compressed DDS + { + for( j = 0; j < Q_max( 1, pic->numMips ); j++ ) + { + width = Q_max( 1, ( tex->width >> j )); + height = Q_max( 1, ( tex->height >> j )); + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); + size = GL_CalcImageSize( pic->type, width, height, tex->depth ); + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, buf ); + tex->size += texsize; + buf += size; // move pointer + tex->numMips++; + + GL_CheckTexImageError( tex ); + + } + } + else // RGBA32 + { + int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL )); + + // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides + if(( tex->depth == 1 ) && ( pic->width != tex->width ) || ( pic->height != tex->height )) + data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap ); + else data = buf; + + if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + data = GL_ApplyFilter( data, tex->width, tex->height ); + + // mips will be auto-generated if desired + for( j = 0; j < mipCount; j++ ) + { + width = Q_max( 1, ( tex->width >> j )); + height = Q_max( 1, ( tex->height >> j )); + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); + size = GL_CalcImageSize( pic->type, width, height, tex->depth ); + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, data ); + if( mipCount > 1 ) + GL_BuildMipMap( data, width, height, tex->depth, tex->flags ); + tex->size += texsize; + tex->numMips++; + + GL_CheckTexImageError( tex ); + } + + // move to next side + if( numSides > 1 && ( buf != NULL )) + buf += GL_CalcImageSize( pic->type, pic->width, pic->height, 1 ); + } + } + + SetBits( tex->flags, TF_IMG_UPLOADED ); // done + tex->numMips /= numSides; + + return true; +#endif + return true; +} + +/* +=============== +GL_ProcessImage + +do specified actions on pixels +=============== +*/ +static void GL_ProcessImage( image_t *tex, rgbdata_t *pic ) +{ + uint img_flags = 0; + + // force upload texture as RGB or RGBA (detail textures requires this) + if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; + if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA; + + if( ImageDXT( pic->type )) + { + if( !pic->numMips ) + tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request + + // clear all the unsupported flags + tex->flags &= ~TF_KEEP_SOURCE; + } + else + { + // copy flag about luma pixels + if( pic->flags & IMAGE_HAS_LUMA ) + tex->flags |= TF_HAS_LUMA; + + if( pic->flags & IMAGE_QUAKEPAL ) + tex->flags |= TF_QUAKEPAL; + + // create luma texture from quake texture + if( tex->flags & TF_MAKELUMA ) + { + img_flags |= IMAGE_MAKE_LUMA; + tex->flags &= ~TF_MAKELUMA; + } + + if( tex->flags & TF_ALLOW_EMBOSS ) + { + img_flags |= IMAGE_EMBOSS; + tex->flags &= ~TF_ALLOW_EMBOSS; + } + + if( !FBitSet( tex->flags, TF_IMG_UPLOADED ) && FBitSet( tex->flags, TF_KEEP_SOURCE )) + tex->original = gEngfuncs.FS_CopyImage( pic ); // because current pic will be expanded to rgba + + // we need to expand image into RGBA buffer + if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 ) + img_flags |= IMAGE_FORCE_RGBA; + + // processing image before uploading (force to rgba, make luma etc) + if( pic->buffer ) gEngfuncs.Image_Process( &pic, 0, 0, img_flags, gl_emboss_scale->value ); + + if( FBitSet( tex->flags, TF_LUMINANCE )) + ClearBits( pic->flags, IMAGE_HAS_COLOR ); + } +} + +/* +================ +GL_CheckTexName +================ +*/ +qboolean GL_CheckTexName( const char *name ) +{ + if( !COM_CheckString( name ) ) + return false; + + // because multi-layered textures can exceed name string + if( Q_strlen( name ) >= sizeof( r_images->name )) + { + gEngfuncs.Con_Printf( S_ERROR "LoadTexture: too long name %s (%d)\n", name, Q_strlen( name )); + return false; + } + + return true; +} + +/* +================ +GL_TextureForName +================ +*/ +static image_t *GL_TextureForName( const char *name ) +{ + image_t *tex; + uint hash; + + // find the texture in array + hash = gEngfuncs.COM_HashKey( name, TEXTURES_HASH_SIZE ); + + for( tex = r_imagesHashTable[hash]; tex != NULL; tex = tex->nextHash ) + { + if( !Q_stricmp( tex->name, name )) + return tex; + } + + return NULL; +} + +/* +================ +GL_AllocTexture +================ +*/ +static image_t *GL_AllocTexture( const char *name, texFlags_t flags ) +{ + image_t *tex; + uint i; + + // find a free texture_t slot + for( i = 0, tex = r_images; i < r_numImages; i++, tex++ ) + if( !tex->name[0] ) break; + + if( i == r_numImages ) + { + if( r_numImages == MAX_TEXTURES ) + gEngfuncs.Host_Error( "GL_AllocTexture: MAX_TEXTURES limit exceeds\n" ); + r_numImages++; + } + + tex = &r_images[i]; + + // copy initial params + Q_strncpy( tex->name, name, sizeof( tex->name )); + + //tex->texnum = i; // texnum is used for fast acess into gl_textures array too + tex->flags = flags; + + // add to hash table + tex->hashValue = gEngfuncs.COM_HashKey( name, TEXTURES_HASH_SIZE ); + tex->nextHash = r_imagesHashTable[tex->hashValue]; + r_imagesHashTable[tex->hashValue] = tex; + + return tex; +} + +/* +================ +GL_DeleteTexture +================ +*/ +static void GL_DeleteTexture( image_t *tex ) +{ + image_t **prev; + image_t *cur; + + ASSERT( tex != NULL ); + + // already freed? + if( !tex->pixels) return; + + // debug + if( !tex->name[0] ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_DeleteTexture: trying to free unnamed texture\n"); + return; + } + + // remove from hash table + prev = &r_imagesHashTable[tex->hashValue]; + + while( 1 ) + { + cur = *prev; + if( !cur ) break; + + if( cur == tex ) + { + *prev = cur->nextHash; + break; + } + prev = &cur->nextHash; + } + + // release source + if( tex->original ) + gEngfuncs.FS_FreeImage( tex->original ); + + memset( tex, 0, sizeof( *tex )); +} + +/* +================ +GL_UpdateTexSize + +recalc image room +================ +*/ +void GL_UpdateTexSize( int texnum, int width, int height, int depth ) +{ + int i, j, texsize; + int numSides; + image_t *tex; + + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + return; + + tex = &r_images[texnum]; + numSides = FBitSet( tex->flags, TF_CUBEMAP ) ? 6 : 1; + GL_SetTextureDimensions( tex, width, height, depth ); + tex->size = 0; // recompute now + + for( i = 0; i < numSides; i++ ) + { + for( j = 0; j < Q_max( 1, tex->numMips ); j++ ) + { + width = Q_max( 1, ( tex->width >> j )); + height = Q_max( 1, ( tex->height >> j )); + texsize = GL_CalcTextureSize( width, height, tex->depth ); + tex->size += texsize; + } + } +} + +/* +================ +GL_LoadTexture +================ +*/ +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) +{ + image_t *tex; + rgbdata_t *pic; + uint picFlags = 0; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name ))) + return (tex - r_images); + + if( FBitSet( flags, TF_NOFLIP_TGA )) + SetBits( picFlags, IL_DONTFLIP_TGA ); + + if( FBitSet( flags, TF_KEEP_SOURCE ) && !FBitSet( flags, TF_EXPAND_SOURCE )) + SetBits( picFlags, IL_KEEP_8BIT ); + + // set some image flags + gEngfuncs.Image_SetForceFlags( picFlags ); + + pic = gEngfuncs.FS_LoadImage( name, buf, size ); + if( !pic ) return 0; // couldn't loading image + + // allocate the new one + tex = GL_AllocTexture( name, flags ); + GL_ProcessImage( tex, pic ); + + if( !GL_UploadTexture( tex, pic )) + { + memset( tex, 0, sizeof( image_t )); + gEngfuncs.FS_FreeImage( pic ); // release source texture + return 0; + } + + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc + gEngfuncs.FS_FreeImage( pic ); // release source texture + + // NOTE: always return texnum as index in array or engine will stop work !!! + return tex - r_images; +} + +/* +================ +GL_LoadTextureArray +================ +*/ +int GL_LoadTextureArray( const char **names, int flags ) +{ + return 0; +} + +/* +================ +GL_LoadTextureFromBuffer +================ +*/ +int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ) +{ + image_t *tex; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name )) && !update ) + return (tex - r_images); + + // couldn't loading image + if( !pic ) return 0; + + if( update ) + { + if( tex == NULL ) + gEngfuncs.Host_Error( "GL_LoadTextureFromBuffer: couldn't find texture %s for update\n", name ); + SetBits( tex->flags, flags ); + } + else + { + // allocate the new one + tex = GL_AllocTexture( name, flags ); + } + + GL_ProcessImage( tex, pic ); + if( !GL_UploadTexture( tex, pic )) + { + memset( tex, 0, sizeof( image_t )); + return 0; + } + + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc + return (tex - r_images); +} + +/* +================ +GL_CreateTexture + +creates texture from buffer +================ +*/ +int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ) +{ + int datasize = 1; + rgbdata_t r_empty; + + if( FBitSet( flags, TF_ARB_16BIT )) + datasize = 2; + else if( FBitSet( flags, TF_ARB_FLOAT )) + datasize = 4; + + memset( &r_empty, 0, sizeof( r_empty )); + r_empty.width = width; + r_empty.height = height; + r_empty.type = PF_RGBA_32; + r_empty.size = r_empty.width * r_empty.height * datasize * 4; + r_empty.buffer = (byte *)buffer; + + // clear invalid combinations + ClearBits( flags, TF_TEXTURE_3D ); + + // if image not luminance and not alphacontrast it will have color + if( !FBitSet( flags, TF_LUMINANCE ) && !FBitSet( flags, TF_ALPHACONTRAST )) + SetBits( r_empty.flags, IMAGE_HAS_COLOR ); + + if( FBitSet( flags, TF_HAS_ALPHA )) + SetBits( r_empty.flags, IMAGE_HAS_ALPHA ); + + if( FBitSet( flags, TF_CUBEMAP )) + { + return 0; + } + + return GL_LoadTextureInternal( name, &r_empty, flags ); +} + +/* +================ +GL_CreateTextureArray + +creates texture array from buffer +================ +*/ +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ) +{ + return 0; +} + +/* +================ +GL_FindTexture +================ +*/ +int GL_FindTexture( const char *name ) +{ + image_t *tex; + + if( !GL_CheckTexName( name )) + return 0; + + // see if already loaded + if(( tex = GL_TextureForName( name ))) + return (tex - r_images); + + return 0; +} + +/* +================ +GL_FreeTexture +================ +*/ +void GL_FreeTexture( unsigned int texnum ) +{ + // number 0 it's already freed + if( texnum <= 0 ) + return; + + GL_DeleteTexture( &r_images[texnum] ); +} + +/* +================ +GL_ProcessTexture +================ +*/ +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) +{ + image_t *image; + rgbdata_t *pic; + int flags = 0; + + if( texnum <= 0 || texnum >= MAX_TEXTURES ) + return; // missed image + image = &r_images[texnum]; + + // select mode + if( gamma != -1.0f ) + { + flags = IMAGE_LIGHTGAMMA; + } + else if( topColor != -1 && bottomColor != -1 ) + { + flags = IMAGE_REMAP; + } + else + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: bad operation for %s\n", image->name ); + return; + } + + if( !image->original ) + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: no input data for %s\n", image->name ); + return; + } + + if( ImageDXT( image->original->type )) + { + gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: can't process compressed texture %s\n", image->name ); + return; + } + + // all the operations makes over the image copy not an original + pic = gEngfuncs.FS_CopyImage( image->original ); + gEngfuncs.Image_Process( &pic, topColor, bottomColor, flags, 0.0f ); + + GL_UploadTexture( image, pic ); + GL_ApplyTextureParams( image ); // update texture filter, wrap etc + + gEngfuncs.FS_FreeImage( pic ); +} + +/* +============================================================================== + +INTERNAL TEXTURES + +============================================================================== +*/ +/* +================== +GL_FakeImage +================== +*/ +static rgbdata_t *GL_FakeImage( int width, int height, int depth, int flags ) +{ + static byte data2D[1024]; // 16x16x4 + static rgbdata_t r_image; + + // also use this for bad textures, but without alpha + r_image.width = Q_max( 1, width ); + r_image.height = Q_max( 1, height ); + r_image.depth = Q_max( 1, depth ); + r_image.flags = flags; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * r_image.depth * 4; + r_image.buffer = (r_image.size > sizeof( data2D )) ? NULL : data2D; + r_image.palette = NULL; + r_image.numMips = 1; + r_image.encode = 0; + + if( FBitSet( r_image.flags, IMAGE_CUBEMAP )) + r_image.size *= 6; + memset( data2D, 0xFF, sizeof( data2D )); + + return &r_image; +} + +/* +================== +R_InitDlightTexture +================== +*/ +void R_InitDlightTexture( void ) +{ + rgbdata_t r_image; + + if( tr.dlightTexture != 0 ) + return; // already initialized + + memset( &r_image, 0, sizeof( r_image )); + r_image.width = BLOCK_SIZE; + r_image.height = BLOCK_SIZE; + r_image.flags = IMAGE_HAS_COLOR; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + + tr.dlightTexture = GL_LoadTextureInternal( "*dlight", &r_image, TF_NOMIPMAP|TF_CLAMP|TF_ATLAS_PAGE ); +} + +/* +================== +GL_CreateInternalTextures +================== +*/ +static void GL_CreateInternalTextures( void ) +{ + int dx2, dy, d; + int x, y; + rgbdata_t *pic; + + // emo-texture from quake1 + pic = GL_FakeImage( 16, 16, 1, IMAGE_HAS_COLOR ); + + for( y = 0; y < 16; y++ ) + { + for( x = 0; x < 16; x++ ) + { + if(( y < 8 ) ^ ( x < 8 )) + ((uint *)pic->buffer)[y*16+x] = 0xFFFF00FF; + else ((uint *)pic->buffer)[y*16+x] = 0xFF000000; + } + } + + tr.defaultTexture = GL_LoadTextureInternal( "*default", pic, TF_COLORMAP ); + + // particle texture from quake1 + pic = GL_FakeImage( 16, 16, 1, IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA ); + + for( x = 0; x < 16; x++ ) + { + dx2 = x - 8; + dx2 = dx2 * dx2; + + for( y = 0; y < 16; y++ ) + { + dy = y - 8; + d = 255 - 35 * sqrt( dx2 + dy * dy ); + pic->buffer[( y * 16 + x ) * 4 + 3] = bound( 0, d, 255 ); + } + } + + tr.particleTexture = GL_LoadTextureInternal( "*particle", pic, TF_CLAMP ); + + // white texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFFFFFFFF; + tr.whiteTexture = GL_LoadTextureInternal( "*white", pic, TF_COLORMAP ); + + // gray texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFF7F7F7F; + tr.grayTexture = GL_LoadTextureInternal( "*gray", pic, TF_COLORMAP ); + + // black texture + pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFF000000; + tr.blackTexture = GL_LoadTextureInternal( "*black", pic, TF_COLORMAP ); + + // cinematic dummy + pic = GL_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR ); + tr.cinTexture = GL_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP ); +} + +/* +=============== +R_TextureList_f +=============== +*/ +void R_TextureList_f( void ) +{ + image_t *image; + int i, texCount, bytes = 0; + + gEngfuncs.Con_Printf( "\n" ); + gEngfuncs.Con_Printf( " -id- -w- -h- -size- -fmt- -type- -data- -encode- -wrap- -depth- -name--------\n" ); + + for( i = texCount = 0, image = r_images; i < r_numImages; i++, image++ ) + { + if( !image->pixels ) continue; + + bytes += image->size; + texCount++; + + gEngfuncs.Con_Printf( "%4i: ", i ); + gEngfuncs.Con_Printf( "%4i %4i ", image->width, image->height ); + gEngfuncs.Con_Printf( "%12s ", Q_memprint( image->size )); + + if( image->flags & TF_NORMALMAP ) + gEngfuncs.Con_Printf( "normal " ); + else gEngfuncs.Con_Printf( "diffuse " ); + + if( image->flags & TF_CLAMP ) + gEngfuncs.Con_Printf( "clamp " ); + else if( image->flags & TF_BORDER ) + gEngfuncs.Con_Printf( "border " ); + else gEngfuncs.Con_Printf( "repeat " ); + gEngfuncs.Con_Printf( " %d ", image->depth ); + gEngfuncs.Con_Printf( " %s\n", image->name ); + } + + gEngfuncs.Con_Printf( "---------------------------------------------------------\n" ); + gEngfuncs.Con_Printf( "%i total textures\n", texCount ); + gEngfuncs.Con_Printf( "%s total memory used\n", Q_memprint( bytes )); + gEngfuncs.Con_Printf( "\n" ); +} + +/* +=============== +R_InitImages +=============== +*/ +void R_InitImages( void ) +{ + memset( r_images, 0, sizeof( r_images )); + memset( r_imagesHashTable, 0, sizeof( r_imagesHashTable )); + r_numImages = 0; + + // create unused 0-entry + Q_strncpy( r_images->name, "*unused*", sizeof( r_images->name )); + r_images->hashValue = gEngfuncs.COM_HashKey( r_images->name, TEXTURES_HASH_SIZE ); + r_images->nextHash = r_imagesHashTable[r_images->hashValue]; + r_imagesHashTable[r_images->hashValue] = r_images; + r_numImages = 1; + + // validate cvars + R_SetTextureParameters(); + GL_CreateInternalTextures(); + + gEngfuncs.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" ); +} + +/* +=============== +R_ShutdownImages +=============== +*/ +void R_ShutdownImages( void ) +{ + image_t *tex; + int i; + + gEngfuncs.Cmd_RemoveCommand( "texturelist" ); + + for( i = 0, tex = r_images; i < r_numImages; i++, tex++ ) + GL_DeleteTexture( tex ); + + memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); + memset( r_imagesHashTable, 0, sizeof( r_imagesHashTable )); + memset( r_images, 0, sizeof( r_images )); + r_numImages = 0; +} diff --git a/r_local.h b/r_local.h new file mode 100644 index 00000000..62b7a668 --- /dev/null +++ b/r_local.h @@ -0,0 +1,710 @@ +/* +gl_local.h - renderer local declarations +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef GL_LOCAL_H +#define GL_LOCAL_H +#include "port.h" +#include "xash3d_types.h" +#include "cvardef.h" +#include "const.h" +#include "com_model.h" +#include "cl_entity.h" +#include "render_api.h" +#include "protocol.h" +#include "dlight.h" +#include "ref_api.h" +#include "mathlib.h" +#include "ref_params.h" +#include "enginefeatures.h" +#include "com_strings.h" +#include "pm_movevars.h" +//#include "cvar.h" +typedef struct mip_s mip_t; +#define offsetof(s,m) (size_t)&(((s *)0)->m) + +#define ASSERT(x) if(!( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ ) +#define Assert(x) if(!( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ ) + +#include + +#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) cvar_t cv = { cvname, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc } +#define CVAR_DEFINE_AUTO( cv, cvstr, cvflags, cvdesc ) cvar_t cv = { #cv, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc } +#define CVAR_TO_BOOL( x ) ((x) && ((x)->value != 0.0f) ? true : false ) + +#define WORLD (gEngfuncs.GetWorld()) +#define WORLDMODEL (gEngfuncs.pfnGetModelByIndex( 1 )) +#define MOVEVARS (gEngfuncs.pfnGetMoveVars()) + +// make mod_ref.h? +#define LM_SAMPLE_SIZE 16 + + +extern byte *r_temppool; + +#define BLOCK_SIZE tr.block_size // lightmap blocksize +#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility +#define BLOCK_SIZE_MAX 1024 + +#define MAX_TEXTURES 4096 +#define MAX_DETAIL_TEXTURES 256 +#define MAX_LIGHTMAPS 256 +#define SUBDIVIDE_SIZE 64 +#define MAX_DECAL_SURFS 4096 +#define MAX_DRAW_STACK 2 // normal view and menu view + +#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles +#define SHADE_LAMBERT 1.495f +#define DEFAULT_ALPHATEST 0.0f + +// refparams +#define RP_NONE 0 +#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot +#define RP_OLDVIEWLEAF BIT( 1 ) +#define RP_CLIPPLANE BIT( 2 ) + +#define RP_NONVIEWERREF (RP_ENVVIEW) +#define R_ModelOpaque( rm ) ( rm == kRenderNormal ) +#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles )) +#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == gEngfuncs.GetPlayerIndex() && e->player ) +#define RP_NORMALPASS() ( FBitSet( RI.params, RP_NONVIEWERREF ) == 0 ) + +#define CL_IsViewEntityLocalPlayer() ( gEngfuncs.GetViewEntIndex() == gEngfuncs.GetPlayerIndex() ) + +#define CULL_VISIBLE 0 // not culled +#define CULL_BACKSIDE 1 // backside of transparent wall +#define CULL_FRUSTUM 2 // culled by frustum +#define CULL_VISFRAME 3 // culled by PVS +#define CULL_OTHER 4 // culled by other reason + + +/* + skins will be outline flood filled and mip mapped + pics and sprites with alpha will be outline flood filled + pic won't be mip mapped + model skin + sprite frame + wall texture + pic +*/ + +typedef enum +{ + it_skin, + it_sprite, + it_wall, + it_pic, + it_sky +} imagetype_t; + + +//=================================================================== + +typedef unsigned short pixel_t; + +typedef struct vrect_s +{ + int x,y,width,height; + struct vrect_s *pnext; +} vrect_t; + +typedef struct +{ + pixel_t *buffer; // invisible buffer + pixel_t *colormap; // 256 * VID_GRADES size + pixel_t *alphamap; // 256 * 256 translucency map + int rowbytes; // may be > width if displayed in a window + // can be negative for stupid dibs + int width; + int height; +} viddef_t; + +extern viddef_t vid; + +typedef struct +{ + int params; // rendering parameters + + qboolean drawWorld; // ignore world for drawing PlayerModel + qboolean isSkyVisible; // sky is visible + qboolean onlyClientDraw; // disabled by client request + qboolean drawOrtho; // draw world as orthogonal projection + + float fov_x, fov_y; // current view fov + + cl_entity_t *currententity; + model_t *currentmodel; + cl_entity_t *currentbeam; // same as above but for beams + + int viewport[4]; + //gl_frustum_t frustum; + + mleaf_t *viewleaf; + mleaf_t *oldviewleaf; + vec3_t pvsorigin; + vec3_t vieworg; // locked vieworigin + vec3_t viewangles; + vec3_t vforward; + vec3_t vright; + vec3_t vup; + + vec3_t cullorigin; + vec3_t cull_vforward; + vec3_t cull_vright; + vec3_t cull_vup; + + float farClip; + + qboolean fogCustom; + qboolean fogEnabled; + qboolean fogSkybox; + vec4_t fogColor; + float fogDensity; + float fogStart; + float fogEnd; + int cached_contents; // in water + int cached_waterlevel; // was in water + + float skyMins[2][6]; + float skyMaxs[2][6]; + + matrix4x4 objectMatrix; // currententity matrix + matrix4x4 worldviewMatrix; // modelview for world + matrix4x4 modelviewMatrix; // worldviewMatrix * objectMatrix + + matrix4x4 projectionMatrix; + matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix + byte visbytes[(MAX_MAP_LEAFS+7)/8];// actual PVS for current frame + + float viewplanedist; + mplane_t clipPlane; +} ref_instance_t; + +typedef struct +{ + cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes + cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes + cl_entity_t *beam_entities[MAX_VISIBLE_PACKET]; + uint num_solid_entities; + uint num_trans_entities; + uint num_beam_entities; +} draw_list_t; + +typedef struct +{ + int defaultTexture; // use for bad textures + int particleTexture; + int whiteTexture; + int grayTexture; + int blackTexture; + int solidskyTexture; // quake1 solid-sky layer + int alphaskyTexture; // quake1 alpha-sky layer + int lightmapTextures[MAX_LIGHTMAPS]; + int dlightTexture; // custom dlight texture + int skyboxTextures[6]; // skybox sides + int cinTexture; // cinematic texture + + int skytexturenum; // this not a gl_texturenum! + int skyboxbasenum; // start with 5800 + + // entity lists + draw_list_t draw_stack[MAX_DRAW_STACK]; + int draw_stack_pos; + draw_list_t *draw_list; + + msurface_t *draw_decals[MAX_DECAL_SURFS]; + int num_draw_decals; + + // OpenGL matrix states + qboolean modelviewIdentity; + + int visframecount; // PVS frame + int dlightframecount; // dynamic light frame + int realframecount; // not including viewpasses + int framecount; + + qboolean ignore_lightgamma; + qboolean fCustomRendering; + qboolean fResetVis; + qboolean fFlipViewModel; + + // tree visualization stuff + int recursion_level; + int max_recursion; + + byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS + int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536 + int block_size; // lightmap blocksize + + double frametime; // special frametime for multipass rendering (will set to 0 on a nextview) + float blend; // global blend value + + // cull info + vec3_t modelorg; // relative to viewpoint + + qboolean fCustomSkybox; +} gl_globals_t; + +typedef struct +{ + uint c_world_polys; + uint c_studio_polys; + uint c_sprite_polys; + uint c_alias_polys; + uint c_world_leafs; + + uint c_view_beams_count; + uint c_active_tents_count; + uint c_alias_models_drawn; + uint c_studio_models_drawn; + uint c_sprite_models_drawn; + uint c_particle_count; + + uint c_client_ents; // entities that moved to client + double t_world_node; + double t_world_draw; +} ref_speeds_t; + +extern ref_speeds_t r_stats; +extern ref_instance_t RI; +extern gl_globals_t tr; + +extern float gldepthmin, gldepthmax; +#define r_numEntities (tr.draw_list->num_solid_entities + tr.draw_list->num_trans_entities) +#define r_numStatics (r_stats.c_client_ents) + +typedef struct image_s +{ + char name[256]; // game path, including extension (can be store image programs) + word srcWidth; // keep unscaled sizes + word srcHeight; + word width; // upload width\height + word height; + word depth; // texture depth or count of layers for 2D_ARRAY + byte numMips; // mipmap count + + + texFlags_t flags; + + rgba_t fogParams; // some water textures + // contain info about underwater fog + rgbdata_t *original; // keep original image + + // debug info + size_t size; // upload size for debug targets + + // detail textures stuff + float xscale; + float yscale; + + imagetype_t type; + qboolean transparent; + pixel_t *pixels[4]; // mip levels + + int servercount; + uint hashValue; + struct gltexture_s *nextHash; +} image_t; + +#if 0 + +// +// gl_backend.c +// +void GL_BackendStartFrame( void ); +void GL_BackendEndFrame( void ); +void GL_CleanUpTextureUnits( int last ); +void GL_Bind( int tmu, unsigned int texnum ); +void GL_LoadTexMatrix( const matrix4x4 m ); +void GL_LoadTexMatrixExt( const float *glmatrix ); +void GL_LoadMatrix( const matrix4x4 source ); +void GL_TexGen( unsigned int coord, unsigned int mode ); +void GL_SelectTexture( int texture ); +void GL_CleanupAllTextureUnits( void ); +void GL_LoadIdentityTexMatrix( void ); +void GL_DisableAllTexGens( void ); +void GL_SetRenderMode( int mode ); +void GL_TextureTarget( uint target ); +void GL_Cull( unsigned int cull ); +void R_ShowTextures( void ); +void R_ShowTree( void ); +void SCR_TimeRefresh_f( void ); + +// +// gl_beams.c +// +void CL_DrawBeams( int fTrans, BEAM *active_beams ); +qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly ); + +// +// gl_cull.c +// +int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax ); +qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ); +qboolean R_CullSphere( const vec3_t centre, const float radius ); +//int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags ); + +// +// gl_decals.c +// +void DrawSurfaceDecals( msurface_t *fa, qboolean single, qboolean reverse ); +float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount ); +void DrawSingleDecal( decal_t *pDecal, msurface_t *fa ); +void R_EntityRemoveDecals( model_t *mod ); +void DrawDecalsBatch( void ); +void R_ClearDecals( void ); + + + +// +// gl_drawhulls.c +// +void R_DrawWorldHull( void ); +void R_DrawModelHull( void ); +#endif + +void GL_Bind( int tmu, unsigned int texnum ); + +// +// gl_draw.c +// +void R_Set2DMode( qboolean enable ); +void R_DrawTileClear( int texnum, int x, int y, int w, int h ); +void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data );// + +// gl_image.c +// +void R_SetTextureParameters( void ); +image_t *R_GetTexture( unsigned int texnum ); +#define GL_LoadTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, false ) +#define GL_UpdateTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, true ) +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); +int GL_LoadTextureArray( const char **names, int flags ); +int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ); +byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap ); +int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ); +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags ); +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); +void GL_UpdateTexSize( int texnum, int width, int height, int depth ); +void GL_ApplyTextureParams( image_t *tex ); +int GL_FindTexture( const char *name ); +void GL_FreeTexture( unsigned int texnum ); +const char *GL_Target( unsigned int target ); +void R_InitDlightTexture( void ); +void R_TextureList_f( void ); +void R_InitImages( void ); +void R_ShutdownImages( void ); +#if 0 +// +// gl_rlight.c +// +void CL_RunLightStyles( void ); +void R_PushDlights( void ); +void R_AnimateLight( void ); +void R_GetLightSpot( vec3_t lightspot ); +void R_MarkLights( dlight_t *light, int bit, mnode_t *node ); +colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec ); +int R_CountSurfaceDlights( msurface_t *surf ); +colorVec R_LightPoint( const vec3_t p0 ); +int R_CountDlights( void ); + +// +// gl_rmain.c +// +void R_ClearScene( void ); +void R_LoadIdentity( void ); +void R_RenderScene( void ); +void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size ); +void R_SetupRefParams( const struct ref_viewpass_s *rvp ); +void R_TranslateForEntity( cl_entity_t *e ); +void R_RotateForEntity( cl_entity_t *e ); +void R_SetupGL( qboolean set_gl_state ); +void R_AllowFog( qboolean allowed ); +void R_SetupFrustum( void ); +void R_FindViewLeaf( void ); +void R_PushScene( void ); +void R_PopScene( void ); +void R_DrawFog( void ); + +// +// gl_rmath.c +// +void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] ); +void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] ); +void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 ); +void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z ); +void Matrix4x4_ConcatScale( matrix4x4 out, float x ); +void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z ); +void Matrix4x4_CreateScale( matrix4x4 out, float x ); +void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z ); +void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar); +void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar); +void Matrix4x4_CreateModelview( matrix4x4 out ); + +// +// gl_rmisc.c +// +void R_ClearStaticEntities( void ); + +// +// gl_rsurf.c +// +void R_MarkLeaves( void ); +void R_DrawWorld( void ); +void R_DrawWaterSurfaces( void ); +void R_DrawBrushModel( cl_entity_t *e ); +void GL_SubdivideSurface( msurface_t *fa ); +void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa ); +void DrawGLPoly( glpoly_t *p, float xScale, float yScale ); +texture_t *R_TextureAnimation( msurface_t *s ); +void GL_SetupFogColorForSurfaces( void ); +void R_DrawAlphaTextureChains( void ); +void GL_RebuildLightmaps( void ); +void GL_InitRandomTable( void ); +void GL_BuildLightmaps( void ); +void GL_ResetFogColor( void ); +void R_GenerateVBO(); +void R_ClearVBO(); +void R_AddDecalVBO( decal_t *pdecal, msurface_t *surf ); + +// +// gl_rpart.c +// +void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime ); +void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float partsize ); +void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ); + + +// +// gl_sprite.c +// +void R_SpriteInit( void ); +void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags ); +mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw ); +void R_DrawSpriteModel( cl_entity_t *e ); + +// +// gl_studio.c +// +void R_StudioInit( void ); +void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded ); +void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles ); +float CL_GetSequenceDuration( cl_entity_t *ent, int sequence ); +struct mstudiotex_s *R_StudioGetTexture( cl_entity_t *e ); +float CL_GetStudioEstimatedFrame( cl_entity_t *ent ); +int R_GetEntityRenderMode( cl_entity_t *ent ); +void R_DrawStudioModel( cl_entity_t *e ); +player_info_t *pfnPlayerInfo( int index ); +void R_GatherPlayerLight( void ); +float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc ); +void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles ); +void R_StudioResetPlayerModels( void ); +void CL_InitStudioAPI( void ); +void Mod_StudioLoadTextures( model_t *mod, void *data ); +void Mod_StudioUnloadTextures( void *data ); + +// +// gl_alias.c +// +void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded ); +void R_DrawAliasModel( cl_entity_t *e ); +void R_AliasInit( void ); + +// +// gl_warp.c +// + +void R_InitSkyClouds( mip_t *mt, struct texture_s *tx, qboolean custom_palette ); +void R_AddSkyBoxSurface( msurface_t *fa ); +void R_ClearSkyBox( void ); +void R_DrawSkyBox( void ); +void R_DrawClouds( void ); +void EmitWaterPolys( msurface_t *warp, qboolean reverse ); +#endif + +void R_InitSkyClouds( struct mip_s *mt, struct texture_s *tx, qboolean custom_palette ); +// +// gl_vgui.c +// +void VGUI_DrawInit( void ); +void VGUI_DrawShutdown( void ); +void VGUI_SetupDrawingText( int *pColor ); +void VGUI_SetupDrawingRect( int *pColor ); +void VGUI_SetupDrawingImage( int *pColor ); +void VGUI_BindTexture( int id ); +void VGUI_EnableTexture( qboolean enable ); +void VGUI_CreateTexture( int id, int width, int height ); +void VGUI_UploadTexture( int id, const char *buffer, int width, int height ); +void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight ); +void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr ); +void VGUI_GetTextureSizes( int *width, int *height ); +int VGUI_GenerateTexture( void ); + +//#include "vid_common.h" + +// +// renderer exports +// +qboolean R_Init( void ); +void R_Shutdown( void ); +void GL_SetupAttributes( int safegl ); +void GL_OnContextCreated( void ); +void GL_InitExtensions( void ); +void GL_ClearExtensions( void ); +void VID_CheckChanges( void ); +int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); +void GL_FreeImage( const char *name ); +qboolean VID_ScreenShot( const char *filename, int shot_type ); +qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot ); +void R_BeginFrame( qboolean clearScene ); +int R_RenderFrame( const struct ref_viewpass_s *vp ); +void R_EndFrame( void ); +void R_ClearScene( void ); +void R_GetTextureParms( int *w, int *h, int texnum ); +void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int curFrame, const struct model_s *pSprite ); +void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty ); +void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum ); +qboolean R_SpeedsMessage( char *out, size_t size ); +void R_SetupSky( const char *skyboxname ); +qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ); +int R_WorldToScreen( const vec3_t point, vec3_t screen ); +void R_ScreenToWorld( const vec3_t screen, vec3_t point ); +qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType ); +void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size, qboolean *loaded ); +void Mod_SpriteUnloadTextures( void *data ); +void Mod_UnloadAliasModel( struct model_s *mod ); +void Mod_AliasUnloadTextures( void *data ); +void GL_SetRenderMode( int mode ); +void R_RunViewmodelEvents( void ); +void R_DrawViewModel( void ); +int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame ); +void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale ); +void R_RemoveEfrags( struct cl_entity_s *ent ); +void R_AddEfrags( struct cl_entity_s *ent ); +void R_DecalRemoveAll( int texture ); +int R_CreateDecalList( decallist_t *pList ); +void R_ClearAllDecals( void ); +byte *Mod_GetCurrentVis( void ); +void Mod_SetOrthoBounds( const float *mins, const float *maxs ); +void R_NewMap( void ); +void CL_AddCustomBeam( cl_entity_t *pEnvBeam ); +#if 0 +// +// gl_opengl.c +// +#define GL_CheckForErrors() GL_CheckForErrors_( __FILE__, __LINE__ ) +void GL_CheckForErrors_( const char *filename, const int fileline ); +const char *GL_ErrorString( int err ); +qboolean GL_Support( int r_ext ); +int GL_MaxTextureUnits( void ); +void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext ); +void GL_SetExtension( int r_ext, int enable ); +#endif +// +// gl_triapi.c +// +void TriRenderMode( int mode ); +void TriBegin( int mode ); +void TriEnd( void ); +void TriTexCoord2f( float u, float v ); +void TriVertex3fv( const float *v ); +void TriVertex3f( float x, float y, float z ); +void _TriColor4f( float r, float g, float b, float a ); +void TriColor4ub( byte r, byte g, byte b, byte a ); +int TriWorldToScreen( float *world, float *screen ); +int TriSpriteTexture( model_t *pSpriteModel, int frame ); +void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ); +void TriGetMatrix( const int pname, float *matrix ); +void TriFogParams( float flDensity, int iFogSkybox ); +void TriCullFace( TRICULLSTYLE mode ); + + +extern ref_api_t gEngfuncs; +extern ref_globals_t *gpGlobals; +extern cvar_t *gl_emboss_scale; +#if 0 +// +// renderer cvars +// +extern cvar_t *gl_texture_anisotropy; +extern cvar_t *gl_extensions; +extern cvar_t *gl_check_errors; +extern cvar_t *gl_texture_lodbias; +extern cvar_t *gl_texture_nearest; +extern cvar_t *gl_lightmap_nearest; +extern cvar_t *gl_keeptjunctions; + +extern cvar_t *gl_round_down; +extern cvar_t *gl_detailscale; +extern cvar_t *gl_wireframe; +extern cvar_t *gl_polyoffset; +extern cvar_t *gl_finish; +extern cvar_t *gl_nosort; +extern cvar_t *gl_clear; +extern cvar_t *gl_test; // cvar to testify new effects +extern cvar_t *gl_msaa; +extern cvar_t *gl_stencilbits; + +extern cvar_t *r_speeds; +extern cvar_t *r_fullbright; +extern cvar_t *r_norefresh; +extern cvar_t *r_showtree; // build graph of visible hull +extern cvar_t *r_lighting_extended; +extern cvar_t *r_lighting_modulate; +extern cvar_t *r_lighting_ambient; +extern cvar_t *r_studio_lambert; +extern cvar_t *r_detailtextures; +extern cvar_t *r_drawentities; +extern cvar_t *r_decals; +extern cvar_t *r_novis; +extern cvar_t *r_nocull; +extern cvar_t *r_lockpvs; +extern cvar_t *r_lockfrustum; +extern cvar_t *r_traceglow; +extern cvar_t *r_dynamic; +extern cvar_t *r_lightmap; +extern cvar_t *r_vbo; +extern cvar_t *r_vbo_dlightmode; + +extern cvar_t *vid_brightness; +extern cvar_t *vid_gamma; + +// +// engine shared convars +// +extern cvar_t *gl_showtextures; +extern cvar_t *tracerred; +extern cvar_t *tracergreen; +extern cvar_t *tracerblue; +extern cvar_t *traceralpha; +extern cvar_t *cl_lightstyle_lerping; +extern cvar_t *r_showhull; +#endif +// +// engine callbacks +// +#include "crtlib.h" + +#define Mem_Malloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ ) +#define Mem_Calloc( pool, size ) gEngfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ ) +#define Mem_Realloc( pool, ptr, size ) gEngfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ ) +#define Mem_Free( mem ) gEngfuncs._Mem_Free( mem, __FILE__, __LINE__ ) +#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ ) +#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ ) +#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ ) + +#endif // GL_LOCAL_H diff --git a/r_triapi.c b/r_triapi.c new file mode 100644 index 00000000..1ff6f817 --- /dev/null +++ b/r_triapi.c @@ -0,0 +1,355 @@ +/* +gl_triapi.c - TriAPI draw methods +Copyright (C) 2011 Uncle Mike +Copyright (C) 2019 a1batross + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "r_local.h" +#include "const.h" + +static struct +{ + int renderMode; // override kRenderMode from TriAPI + vec4_t triRGBA; +} ds; + +/* +=============================================================== + + TRIAPI IMPLEMENTATION + +=============================================================== +*/ +/* +============= +TriRenderMode + +set rendermode +============= +*/ +void TriRenderMode( int mode ) +{ + ds.renderMode = mode; +#if 0 + switch( mode ) + { + case kRenderNormal: + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglDisable( GL_BLEND ); + pglDepthMask( GL_TRUE ); + break; + case kRenderTransAlpha: + pglEnable( GL_BLEND ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglDepthMask( GL_FALSE ); + break; + case kRenderTransColor: + case kRenderTransTexture: + pglEnable( GL_BLEND ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + break; + case kRenderGlow: + case kRenderTransAdd: + pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); + pglEnable( GL_BLEND ); + pglDepthMask( GL_FALSE ); + break; + } +#endif +} + +/* +============= +TriBegin + +begin triangle sequence +============= +*/ +void TriBegin( int mode ) +{ +#if 0 + switch( mode ) + { + case TRI_POINTS: + mode = GL_POINTS; + break; + case TRI_TRIANGLES: + mode = GL_TRIANGLES; + break; + case TRI_TRIANGLE_FAN: + mode = GL_TRIANGLE_FAN; + break; + case TRI_QUADS: + mode = GL_QUADS; + break; + case TRI_LINES: + mode = GL_LINES; + break; + case TRI_TRIANGLE_STRIP: + mode = GL_TRIANGLE_STRIP; + break; + case TRI_QUAD_STRIP: + mode = GL_QUAD_STRIP; + break; + case TRI_POLYGON: + default: + mode = GL_POLYGON; + break; + } + + pglBegin( mode ); +#endif +} + +/* +============= +TriEnd + +draw triangle sequence +============= +*/ +void TriEnd( void ) +{ + //pglEnd( ); +} + +/* +============= +_TriColor4f + +============= +*/ +void _TriColor4f( float r, float g, float b, float a ) +{ + //pglColor4f( r, g, b, a ); +} + +/* +============= +TriColor4ub + +============= +*/ +void TriColor4ub( byte r, byte g, byte b, byte a ) +{ + ds.triRGBA[0] = r * (1.0f / 255.0f); + ds.triRGBA[1] = g * (1.0f / 255.0f); + ds.triRGBA[2] = b * (1.0f / 255.0f); + ds.triRGBA[3] = a * (1.0f / 255.0f); + + _TriColor4f( ds.triRGBA[0], ds.triRGBA[1], ds.triRGBA[2], 1.0f ); +} + +/* +================= +TriColor4f +================= +*/ +void TriColor4f( float r, float g, float b, float a ) +{ + if( ds.renderMode == kRenderTransAlpha ) + TriColor4ub( r * 255.9f, g * 255.9f, b * 255.9f, a * 255.0f ); + else _TriColor4f( r * a, g * a, b * a, 1.0 ); + + ds.triRGBA[0] = r; + ds.triRGBA[1] = g; + ds.triRGBA[2] = b; + ds.triRGBA[3] = a; +} + +/* +============= +TriTexCoord2f + +============= +*/ +void TriTexCoord2f( float u, float v ) +{ + //pglTexCoord2f( u, v ); +} + +/* +============= +TriVertex3fv + +============= +*/ +void TriVertex3fv( const float *v ) +{ + //pglVertex3fv( v ); +} + +/* +============= +TriVertex3f + +============= +*/ +void TriVertex3f( float x, float y, float z ) +{ + //pglVertex3f( x, y, z ); +} + +/* +============= +TriWorldToScreen + +convert world coordinates (x,y,z) into screen (x, y) +============= +*/ +int TriWorldToScreen( float *world, float *screen ) +{ + int retval; + +// retval = R_WorldToScreen( world, screen ); + + screen[0] = 0.5f * screen[0] * (float)RI.viewport[2]; + screen[1] = -0.5f * screen[1] * (float)RI.viewport[3]; + screen[0] += 0.5f * (float)RI.viewport[2]; + screen[1] += 0.5f * (float)RI.viewport[3]; + + return retval; +} + +/* +============= +TriSpriteTexture + +bind current texture +============= +*/ +int TriSpriteTexture( model_t *pSpriteModel, int frame ) +{ + int gl_texturenum; + + if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) == 0 ) + return 0; + + if( gl_texturenum <= 0 || gl_texturenum > MAX_TEXTURES ) + gl_texturenum = tr.defaultTexture; + + GL_Bind( XASH_TEXTURE0, gl_texturenum ); + + return 1; +} + +/* +============= +TriFog + +enables global fog on the level +============= +*/ +void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) +{ +#if 0 + // overrided by internal fog + if( RI.fogEnabled ) return; + RI.fogCustom = bOn; + + // check for invalid parms + if( flEnd <= flStart ) + { + RI.fogCustom = false; + pglDisable( GL_FOG ); + return; + } + + if( RI.fogCustom ) + pglEnable( GL_FOG ); + else pglDisable( GL_FOG ); + + // copy fog params + RI.fogColor[0] = flFogColor[0] / 255.0f; + RI.fogColor[1] = flFogColor[1] / 255.0f; + RI.fogColor[2] = flFogColor[2] / 255.0f; + RI.fogStart = flStart; + RI.fogColor[3] = 1.0f; + RI.fogDensity = 0.0f; + RI.fogSkybox = true; + RI.fogEnd = flEnd; + + pglFogi( GL_FOG_MODE, GL_LINEAR ); + pglFogfv( GL_FOG_COLOR, RI.fogColor ); + pglFogf( GL_FOG_START, RI.fogStart ); + pglFogf( GL_FOG_END, RI.fogEnd ); + pglHint( GL_FOG_HINT, GL_NICEST ); +#endif +} + +/* +============= +TriGetMatrix + +very strange export +============= +*/ +void TriGetMatrix( const int pname, float *matrix ) +{ + //pglGetFloatv( pname, matrix ); +} + +/* +============= +TriForParams + +============= +*/ +void TriFogParams( float flDensity, int iFogSkybox ) +{ + RI.fogDensity = flDensity; + RI.fogSkybox = iFogSkybox; +} + +/* +============= +TriCullFace + +============= +*/ +void TriCullFace( TRICULLSTYLE mode ) +{ +#if 0 + int glMode; + + switch( mode ) + { + case TRI_FRONT: + glMode = GL_FRONT; + break; + default: + glMode = GL_NONE; + break; + } + + GL_Cull( mode ); +#endif +} + +/* +============= +TriBrightness +============= +*/ +void TriBrightness( float brightness ) +{ + float r, g, b; + + r = ds.triRGBA[0] * ds.triRGBA[3] * brightness; + g = ds.triRGBA[1] * ds.triRGBA[3] * brightness; + b = ds.triRGBA[2] * ds.triRGBA[3] * brightness; + + _TriColor4f( r, g, b, 1.0f ); +} + diff --git a/r_vgui.c b/r_vgui.c new file mode 100644 index 00000000..70d2740b --- /dev/null +++ b/r_vgui.c @@ -0,0 +1,225 @@ +/* +gl_vgui.c - OpenGL vgui draw methods +Copyright (C) 2011 Uncle Mike +Copyright (C) 2019 a1batross + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "r_local.h" + +#define VGUI_MAX_TEXTURES ( MAX_TEXTURES / 2 ) // a half of total textures count + +static int g_textures[VGUI_MAX_TEXTURES]; +static int g_textureId = 0; +static int g_iBoundTexture; + +/* +================ +VGUI_DrawInit + +Startup VGUI backend +================ +*/ +void GAME_EXPORT VGUI_DrawInit( void ) +{ + memset( g_textures, 0, sizeof( g_textures )); + g_textureId = g_iBoundTexture = 0; +} + +/* +================ +VGUI_DrawShutdown + +Release all textures +================ +*/ +void GAME_EXPORT VGUI_DrawShutdown( void ) +{ + int i; + + for( i = 1; i < g_textureId; i++ ) + { + GL_FreeTexture( g_textures[i] ); + } +} + +/* +================ +VGUI_GenerateTexture + +generate unique texture number +================ +*/ +int GAME_EXPORT VGUI_GenerateTexture( void ) +{ + if( ++g_textureId >= VGUI_MAX_TEXTURES ) + gEngfuncs.Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" ); + return g_textureId; +} + +/* +================ +VGUI_UploadTexture + +Upload texture into video memory +================ +*/ +void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int height ) +{ + rgbdata_t r_image; + char texName[32]; + + if( id <= 0 || id >= VGUI_MAX_TEXTURES ) + { + gEngfuncs.Con_DPrintf( S_ERROR "VGUI_UploadTexture: bad texture %i. Ignored\n", id ); + return; + } + + Q_snprintf( texName, sizeof( texName ), "*vgui%i", id ); + memset( &r_image, 0, sizeof( r_image )); + + r_image.width = width; + r_image.height = height; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA; + r_image.buffer = (byte *)buffer; + + g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE ); +} + +/* +================ +VGUI_CreateTexture + +Create empty rgba texture and upload them into video memory +================ +*/ +void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height ) +{ + rgbdata_t r_image; + char texName[32]; + + if( id <= 0 || id >= VGUI_MAX_TEXTURES ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGUI_CreateTexture: bad texture %i. Ignored\n", id ); + return; + } + + Q_snprintf( texName, sizeof( texName ), "*vgui%i", id ); + memset( &r_image, 0, sizeof( r_image )); + + r_image.width = width; + r_image.height = height; + r_image.type = PF_RGBA_32; + r_image.size = r_image.width * r_image.height * 4; + r_image.flags = IMAGE_HAS_ALPHA; + r_image.buffer = NULL; + + g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST ); + g_iBoundTexture = id; +} + +void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight ) +{ + if( id <= 0 || id >= VGUI_MAX_TEXTURES || g_textures[id] == 0 || g_textures[id] == tr.whiteTexture ) + { + gEngfuncs.Con_Reportf( S_ERROR "VGUI_UploadTextureBlock: bad texture %i. Ignored\n", id ); + return; + } + + //pglTexSubImage2D( GL_TEXTURE_2D, 0, drawX, drawY, blockWidth, blockHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgba ); + g_iBoundTexture = id; +} + +void GAME_EXPORT VGUI_SetupDrawingRect( int *pColor ) +{ + +} + +void GAME_EXPORT VGUI_SetupDrawingText( int *pColor ) +{ + +} + +void GAME_EXPORT VGUI_SetupDrawingImage( int *pColor ) +{ + +} + +void GAME_EXPORT VGUI_BindTexture( int id ) +{ + if( id > 0 && id < VGUI_MAX_TEXTURES && g_textures[id] ) + { + GL_Bind( XASH_TEXTURE0, g_textures[id] ); + g_iBoundTexture = id; + } + else + { + // NOTE: same as bogus index 2700 in GoldSrc + id = g_iBoundTexture = 1; + GL_Bind( XASH_TEXTURE0, g_textures[id] ); + } +} + +/* +================ +VGUI_GetTextureSizes + +returns wide and tall for currently binded texture +================ +*/ +void GAME_EXPORT VGUI_GetTextureSizes( int *width, int *height ) +{ + image_t *glt; + int texnum; + + if( g_iBoundTexture ) + texnum = g_textures[g_iBoundTexture]; + else texnum = tr.defaultTexture; + + glt = R_GetTexture( texnum ); + if( width ) *width = glt->srcWidth; + if( height ) *height = glt->srcHeight; +} + +/* +================ +VGUI_EnableTexture + +disable texturemode for fill rectangle +================ +*/ +void GAME_EXPORT VGUI_EnableTexture( qboolean enable ) +{ + +} + +/* +================ +VGUI_DrawQuad + +generic method to fill rectangle +================ +*/ +void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr ) +{ + int width, height; + float xscale, yscale; + + gEngfuncs.CL_GetScreenInfo( &width, &height ); + + xscale = gpGlobals->width / (float)width; + yscale = gpGlobals->height / (float)height; + + ASSERT( ul != NULL && lr != NULL ); +} diff --git a/wscript b/wscript new file mode 100644 index 00000000..8bed8fa4 --- /dev/null +++ b/wscript @@ -0,0 +1,55 @@ +#! /usr/bin/env python +# encoding: utf-8 +# mittorn, 2018 + +from waflib import Logs +import os +from fwgslib import get_subproject_name + +top = '.' + +def options(opt): + # stub + return + +def configure(conf): + # check for dedicated server build + if conf.options.DEDICATED: + return + + if conf.options.SUPPORT_BSP2_FORMAT: + conf.env.append_unique('DEFINES', 'SUPPORT_BSP2_FORMAT') + + conf.env.append_unique('DEFINES', 'REF_DLL') + +def build(bld): + if bld.env.DEDICATED: + return + + bld.load_envs() + name = get_subproject_name(bld) + bld.env = bld.all_envs[name] + + libs = [ 'M' ] + + source = bld.path.ant_glob(['*.c']) + + source += [ '../engine/common/mathlib.c', '../engine/common/crtlib.c', '../engine/common/matrixlib.c' ] + + includes = ['.', + '../engine', + '../engine/common', + '../engine/server', + '../engine/client', + '../common', + '../pm_shared' ] + + bld.shlib( + source = source, + target = name, + features = 'c', + includes = includes, + use = libs, + install_path = bld.env.LIBDIR, + subsystem = bld.env.MSVC_SUBSYSTEM + )