diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 715c45ef3..a7f7acd22 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -132,6 +132,40 @@ typedef struct FLOAT t; // t texture ordinate (t over w) } FOutVector; +typedef struct vbo_vertex_s +{ + float x, y, z; + float u, v; + unsigned char r, g, b, a; +} gl_skyvertex_t; + +typedef enum gl_skyloopmode_e +{ + HWD_SKYLOOP_FAN, + HWD_SKYLOOP_STRIP +} gl_skyloopmode_t; + +typedef struct +{ + gl_skyloopmode_t mode; + int vertexcount; + int vertexindex; + boolean use_texture; +} gl_skyloopdef_t; + +typedef struct +{ + unsigned int vbo; + int rows, columns; + int loopcount; + + int detail, vertex_count; + int texture, width, height; + boolean rebuild; // VBO needs to be rebuilt + + gl_skyloopdef_t *loops; + gl_skyvertex_t *data; +} gl_sky_t; // ========================================================================== // RENDER MODES diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 6f039cc3a..4023e3062 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -37,7 +37,7 @@ EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl); EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color); EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray); -EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform); +EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky); EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index ddc935f0d..e18ed31ce 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5180,10 +5180,155 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) #endif // ========================================================================== -// +// Sky dome rendering, ported from PrBoom+ // ========================================================================== + +static gl_sky_t gl_sky; + +static void HWR_SkyDomeVertex(gl_sky_t *sky, gl_skyvertex_t *vbo, int r, int c, signed char yflip, float delta, boolean foglayer) +{ + const float radians = (float)(M_PIl / 180.0f); + const float scale = 10000.0f; + const float maxSideAngle = 60.0f; + + float topAngle = (c / (float)sky->columns * 360.0f); + float sideAngle = (maxSideAngle * (sky->rows - r) / sky->rows); + float height = (float)(sin(sideAngle * radians)); + float realRadius = (float)(scale * cos(sideAngle * radians)); + float x = (float)(realRadius * cos(topAngle * radians)); + float y = (!yflip) ? scale * height : -scale * height; + float z = (float)(realRadius * sin(topAngle * radians)); + float timesRepeat = (4 * (256.0f / sky->width)); + if (fpclassify(timesRepeat) == FP_ZERO) + timesRepeat = 1.0f; + + if (!foglayer) + { + vbo->r = 255; + vbo->g = 255; + vbo->b = 255; + vbo->a = (r == 0 ? 0 : 255); + + // And the texture coordinates. + vbo->u = (-timesRepeat * c / (float)sky->columns); + if (!yflip) // Flipped Y is for the lower hemisphere. + vbo->v = (r / (float)sky->rows) + 0.5f; + else + vbo->v = 1.0f + ((sky->rows - r) / (float)sky->rows) + 0.5f; + } + + if (r != 4) + y += 300.0f; + + // And finally the vertex. + vbo->x = x; + vbo->y = y + delta; + vbo->z = z; +} + +// Clears the sky dome. +void HWR_ClearSkyDome(void) +{ + gl_sky_t *sky = &gl_sky; + + if (sky->loops) + free(sky->loops); + if (sky->data) + free(sky->data); + + sky->loops = NULL; + sky->data = NULL; + + sky->vbo = 0; + sky->rows = sky->columns = 0; + sky->loopcount = 0; + + sky->detail = 0; + sky->texture = -1; + sky->width = sky->height = 0; + + sky->rebuild = true; +} + +void HWR_BuildSkyDome(void) +{ + int c, r; + signed char yflip; + int row_count = 4; + int col_count = 4; + float delta; + + gl_sky_t *sky = &gl_sky; + gl_skyvertex_t *vertex_p; + texture_t *texture = textures[texturetranslation[skytexture]]; + + sky->detail = 16; + col_count *= sky->detail; + + if ((sky->columns != col_count) || (sky->rows != row_count)) + HWR_ClearSkyDome(); + + sky->columns = col_count; + sky->rows = row_count; + sky->vertex_count = 2 * sky->rows * (sky->columns * 2 + 2) + sky->columns * 2; + + if (!sky->loops) + sky->loops = malloc((sky->rows * 2 + 2) * sizeof(sky->loops[0])); + + // create vertex array + if (!sky->data) + sky->data = malloc(sky->vertex_count * sizeof(sky->data[0])); + + sky->texture = texturetranslation[skytexture]; + sky->width = texture->width; + sky->height = texture->height; + + vertex_p = &sky->data[0]; + sky->loopcount = 0; + + for (yflip = 0; yflip < 2; yflip++) + { + sky->loops[sky->loopcount].mode = HWD_SKYLOOP_FAN; + sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0]; + sky->loops[sky->loopcount].vertexcount = col_count; + sky->loops[sky->loopcount].use_texture = false; + sky->loopcount++; + + delta = 0.0f; + + for (c = 0; c < col_count; c++) + { + HWR_SkyDomeVertex(sky, vertex_p, 1, c, yflip, 0.0f, true); + vertex_p->r = 255; + vertex_p->g = 255; + vertex_p->b = 255; + vertex_p->a = 255; + vertex_p++; + } + + delta = (yflip ? 5.0f : -5.0f) / 128.0f; + + for (r = 0; r < row_count; r++) + { + sky->loops[sky->loopcount].mode = HWD_SKYLOOP_STRIP; + sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0]; + sky->loops[sky->loopcount].vertexcount = 2 * col_count + 2; + sky->loops[sky->loopcount].use_texture = true; + sky->loopcount++; + + for (c = 0; c <= col_count; c++) + { + HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0), yflip, delta, false); + HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0), yflip, delta, false); + } + } + } +} + static void HWR_DrawSkyBackground(player_t *player) { + HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); + if (cv_glskydome.value) { FTransform dometransform; @@ -5221,7 +5366,16 @@ static void HWR_DrawSkyBackground(player_t *player) dometransform.splitscreen = splitscreen; HWR_GetTexture(texturetranslation[skytexture]); - HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform); + + if (gl_sky.texture != texturetranslation[skytexture]) + { + HWR_ClearSkyDome(); + HWR_BuildSkyDome(); + } + + HWD.pfnSetShader(7); // sky shader + HWD.pfnSetTransform(&dometransform); + HWD.pfnRenderSkyDome(&gl_sky); } else { @@ -5302,10 +5456,11 @@ static void HWR_DrawSkyBackground(player_t *player) v[0].t = v[1].t -= ((float) angle / angleturn); } - HWD.pfnSetShader(7); // sky shader + HWD.pfnUnSetShader(); HWD.pfnDrawPolygon(NULL, v, 4, 0); - HWD.pfnSetShader(0); } + + HWD.pfnSetShader(0); } diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index ddb3696b6..d70bb6d72 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -31,6 +31,8 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height); void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight); void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); +void HWR_ClearSkyDome(void); +void HWR_BuildSkyDome(void); void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum); void HWR_InitTextureMapping(void); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 461966224..83087bbbb 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -95,6 +95,8 @@ static GLuint finalScreenTexture = 0; static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); +static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; + // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, @@ -770,6 +772,18 @@ static INT32 shader_leveltime = 0; "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ "}\0" +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// + +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + static const char *fragment_shaders[] = { // Default fragment shader GLSL_DEFAULT_FRAGMENT_SHADER, @@ -793,10 +807,7 @@ static const char *fragment_shaders[] = { GLSL_FOG_FRAGMENT_SHADER, // Sky fragment shader - "uniform sampler2D tex;\n" - "void main(void) {\n" - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - "}\0", + GLSL_SKY_FRAGMENT_SHADER, // Model fragment shader + diffuse lighting from above GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER, @@ -1955,6 +1966,14 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF if (!shader->program) return; + // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f) + if (poly == NULL) + poly = &shader_defaultcolor; + if (tint == NULL) + tint = &shader_defaultcolor; + if (fade == NULL) + fade = &shader_defaultcolor; + #define UNIFORM_1(uniform, a, function) \ if (uniform != -1) \ function (uniform, a); @@ -1975,12 +1994,14 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f); UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f); UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f); + if (Surface != NULL) { UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f); UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f); UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f); } + UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f); #undef UNIFORM_1 @@ -2135,233 +2156,83 @@ EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutV // the DrawPolygon variant of this has some code about polyflags and wrapping here but havent noticed any problems from omitting it? } -typedef struct vbo_vertex_s -{ - float x, y, z; - float u, v; - unsigned char r, g, b, a; -} vbo_vertex_t; - -typedef struct -{ - int mode; - int vertexcount; - int vertexindex; - int use_texture; -} GLSkyLoopDef; - -typedef struct -{ - unsigned int id; - int rows, columns; - int loopcount; - GLSkyLoopDef *loops; - vbo_vertex_t *data; -} GLSkyVBO; - static const boolean gl_ext_arb_vertex_buffer_object = true; -#define NULL_VBO_VERTEX ((vbo_vertex_t*)NULL) -#define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &vbo->data[0].x) -#define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &vbo->data[0].u) -#define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &vbo->data[0].r) +#define NULL_VBO_VERTEX ((gl_skyvertex_t*)NULL) +#define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &sky->data[0].x) +#define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &sky->data[0].u) +#define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &sky->data[0].r) -// The texture offset to be applied to the texture coordinates in SkyVertex(). -static int rows, columns; -static signed char yflip; -static int texw, texh; -static boolean foglayer; -static float delta = 0.0f; - -static int gl_sky_detail = 16; - -static INT32 lasttex = -1; - -#define MAP_COEFF 128.0f - -static void SkyVertex(vbo_vertex_t *vbo, int r, int c) -{ - const float radians = (float)(M_PIl / 180.0f); - const float scale = 10000.0f; - const float maxSideAngle = 60.0f; - - float topAngle = (c / (float)columns * 360.0f); - float sideAngle = (maxSideAngle * (rows - r) / rows); - float height = (float)(sin(sideAngle * radians)); - float realRadius = (float)(scale * cos(sideAngle * radians)); - float x = (float)(realRadius * cos(topAngle * radians)); - float y = (!yflip) ? scale * height : -scale * height; - float z = (float)(realRadius * sin(topAngle * radians)); - float timesRepeat = (4 * (256.0f / texw)); - if (fpclassify(timesRepeat) == FP_ZERO) - timesRepeat = 1.0f; - - if (!foglayer) - { - vbo->r = 255; - vbo->g = 255; - vbo->b = 255; - vbo->a = (r == 0 ? 0 : 255); - - // And the texture coordinates. - vbo->u = (-timesRepeat * c / (float)columns); - if (!yflip) // Flipped Y is for the lower hemisphere. - vbo->v = (r / (float)rows) + 0.5f; - else - vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f; - } - - if (r != 4) - { - y += 300.0f; - } - - // And finally the vertex. - vbo->x = x; - vbo->y = y + delta; - vbo->z = z; -} - -static GLSkyVBO sky_vbo; - -static void gld_BuildSky(int row_count, int col_count) -{ - int c, r; - vbo_vertex_t *vertex_p; - int vertex_count = 2 * row_count * (col_count * 2 + 2) + col_count * 2; - - GLSkyVBO *vbo = &sky_vbo; - - if ((vbo->columns != col_count) || (vbo->rows != row_count)) - { - free(vbo->loops); - free(vbo->data); - memset(vbo, 0, sizeof(&vbo)); - } - - if (!vbo->data) - { - memset(vbo, 0, sizeof(&vbo)); - vbo->loops = malloc((row_count * 2 + 2) * sizeof(vbo->loops[0])); - // create vertex array - vbo->data = malloc(vertex_count * sizeof(vbo->data[0])); - } - - vbo->columns = col_count; - vbo->rows = row_count; - - vertex_p = &vbo->data[0]; - vbo->loopcount = 0; - - for (yflip = 0; yflip < 2; yflip++) - { - vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN; - vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; - vbo->loops[vbo->loopcount].vertexcount = col_count; - vbo->loops[vbo->loopcount].use_texture = false; - vbo->loopcount++; - - delta = 0.0f; - foglayer = true; - for (c = 0; c < col_count; c++) - { - SkyVertex(vertex_p, 1, c); - vertex_p->r = 255; - vertex_p->g = 255; - vertex_p->b = 255; - vertex_p->a = 255; - vertex_p++; - } - foglayer = false; - - delta = (yflip ? 5.0f : -5.0f) / MAP_COEFF; - - for (r = 0; r < row_count; r++) - { - vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_STRIP; - vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; - vbo->loops[vbo->loopcount].vertexcount = 2 * col_count + 2; - vbo->loops[vbo->loopcount].use_texture = true; - vbo->loopcount++; - - for (c = 0; c <= col_count; c++) - { - SkyVertex(vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0)); - SkyVertex(vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0)); - } - } - } -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -static void RenderDome(INT32 skytexture) +EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) { int i, j; - int vbosize; - GLSkyVBO *vbo = &sky_vbo; - rows = 4; - columns = 4 * gl_sky_detail; - - vbosize = 2 * rows * (columns * 2 + 2) + columns * 2; + Shader_Load(NULL, NULL, NULL, NULL); // Build the sky dome! Yes! - if (lasttex != skytexture) + if (sky->rebuild) { // delete VBO when already exists if (gl_ext_arb_vertex_buffer_object) { - if (vbo->id) - pglDeleteBuffers(1, &vbo->id); + if (sky->vbo) + pglDeleteBuffers(1, &sky->vbo); } - lasttex = skytexture; - gld_BuildSky(rows, columns); - if (gl_ext_arb_vertex_buffer_object) { // generate a new VBO and get the associated ID - pglGenBuffers(1, &vbo->id); + pglGenBuffers(1, &sky->vbo); // bind VBO in order to use - pglBindBuffer(GL_ARRAY_BUFFER, vbo->id); + pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo); // upload data to VBO - pglBufferData(GL_ARRAY_BUFFER, vbosize * sizeof(vbo->data[0]), vbo->data, GL_STATIC_DRAW); + pglBufferData(GL_ARRAY_BUFFER, sky->vertex_count * sizeof(sky->data[0]), sky->data, GL_STATIC_DRAW); } + + sky->rebuild = false; } // bind VBO in order to use if (gl_ext_arb_vertex_buffer_object) - pglBindBuffer(GL_ARRAY_BUFFER, vbo->id); + pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo); // activate and specify pointers to arrays - pglVertexPointer(3, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_x); - pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_u); - pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vbo->data[0]), sky_vbo_r); + pglVertexPointer(3, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_u); + pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(sky->data[0]), sky_vbo_r); // activate color arrays pglEnableClientState(GL_COLOR_ARRAY); // set transforms - pglScalef(1.0f, (float)texh / 230.0f, 1.0f); + pglScalef(1.0f, (float)sky->height / 200.0f, 1.0f); pglRotatef(270.0f, 0.0f, 1.0f, 0.0f); for (j = 0; j < 2; j++) { - for (i = 0; i < vbo->loopcount; i++) + for (i = 0; i < sky->loopcount; i++) { - GLSkyLoopDef *loop = &vbo->loops[i]; + gl_skyloopdef_t *loop = &sky->loops[i]; + unsigned int mode = 0; if (j == 0 ? loop->use_texture : !loop->use_texture) continue; - pglDrawArrays(loop->mode, loop->vertexindex, loop->vertexcount); + switch (loop->mode) + { + case HWD_SKYLOOP_FAN: + mode = GL_TRIANGLE_FAN; + break; + case HWD_SKYLOOP_STRIP: + mode = GL_TRIANGLE_STRIP; + break; + default: + continue; + } + + pglDrawArrays(mode, loop->vertexindex, loop->vertexcount); } } @@ -2376,16 +2247,6 @@ static void RenderDome(INT32 skytexture) pglDisableClientState(GL_COLOR_ARRAY); } -EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform) -{ - SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); - SetTransform(&transform); - texw = texture_width; - texh = texture_height; - RenderDome(tex); - SetBlend(0); -} - // ========================================================================== // // ========================================================================== diff --git a/src/p_setup.c b/src/p_setup.c index ceb96df40..b0263435e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4257,6 +4257,10 @@ void HWR_SetupLevel(void) #endif HWR_CreatePlanePolygons((INT32)numnodes - 1); + + // Build the sky dome + HWR_ClearSkyDome(); + HWR_BuildSkyDome(); } #endif diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index 3f6c5e290..fa648a89c 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -102,7 +102,7 @@ static loadfunc_t hwdFuncTable[] = { {"FinishUpdate@4", &hwdriver.pfnFinishUpdate}, {"Draw2DLine@12", &hwdriver.pfnDraw2DLine}, {"DrawPolygon@16", &hwdriver.pfnDrawPolygon}, - {"RenderSkyDome@16", &hwdriver.pfnRenderSkyDome}, + {"RenderSkyDome@4", &hwdriver.pfnRenderSkyDome}, {"SetBlend@4", &hwdriver.pfnSetBlend}, {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture},