#include "common.h" /*************************************************************************** mainSDL.cpp - description ------------------- begin : Mon Jun 3 2002 copyright : (C) 2002 by Yaz0r email : yaz0r@yaz0r.net ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "osystem.h" #include #include #include "shaders/embeddedShaders.h" #include "imguiBGFX.h" #include #include unsigned int gameViewId = 1; bgfx::TextureHandle g_backgroundTexture = BGFX_INVALID_HANDLE; bgfx::TextureHandle g_paletteTexture = BGFX_INVALID_HANDLE; extern int outputResolution[2]; extern bool debuggerVar_debugMenuDisplayed; #define _USE_MATH_DEFINES #include // globals char backBuffer[512 * 256 * 3]; unsigned int ditherTexture = 0; unsigned int debugFontTexture = 0; struct maskStruct { bgfx::TextureHandle maskTexture = BGFX_INVALID_HANDLE; bgfx::VertexBufferHandle vertexBuffer = BGFX_INVALID_HANDLE; int maskX1; int maskY1; int maskX2; int maskY2; }; std::vector> maskTextures; // [room][mask] //vertex buffers for rendering struct polyVertex { float X; float Y; float Z; float U; float V; unsigned char R; unsigned char G; unsigned char B; unsigned char A; }; struct sphereVertex { float X; float Y; float Z; float U; float V; float centerX; float centerY; float size; float material; }; #define NUM_MAX_FLAT_VERTICES 5000*3 #define NUM_MAX_NOISE_VERTICES 2000*3 #define NUM_MAX_TRANSPARENT_VERTICES 1000*2 #define NUM_MAX_RAMP_VERTICES 3000*3 #define NUM_MAX_SPHERES_VERTICES 3000 std::array flatVertices; std::array noiseVertices; std::array transparentVertices; std::array rampVertices; std::array sphereVertices; int numUsedFlatVertices = 0; int numUsedNoiseVertices = 0; int numUsedTransparentVertices = 0; int numUsedRampVertices = 0; int numUsedSpheres = 0; //static unsigned long int zoom = 0; float nearVal = 100; float farVal = 100000; float cameraZoom = 0; float fov = 0; char RGB_Pal[256 * 4]; unsigned int backTexture; int g_screenWidth = 0; int g_screenHeight = 0; void osystem_preinigGL() { } void osystem_initGL(int screenWidth, int screenHeight) { #if 0 #ifndef __APPLE__ gl3wInit(); #endif g_screenWidth = screenWidth; g_screenHeight = screenHeight; //glEnable(GL_TEXTURE_2D); //glEnable(GL_CULL_FACE); checkGL(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); checkGL(); // glEnable(GL_DEPTH_TEST); //glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LESS); glViewport(0, 0, g_screenWidth, g_screenHeight); checkGL(); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background checkGL(); // generate textures { int i; int j; unsigned char ditherMap[256 * 256 * 4]; unsigned char* tempPtr = ditherMap; for (i = 0; i < 256; i++) { for (j = 0; j < 256; j++) { unsigned char ditherValue = rand() % 0x50; *(tempPtr++) = ditherValue; *(tempPtr++) = ditherValue; *(tempPtr++) = ditherValue; *(tempPtr++) = 255; } } //glBlendFunc(GL_SRC_ALPHA,GL_ONE); glGenTextures(1, &ditherTexture); glBindTexture(GL_TEXTURE_2D, ditherTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, ditherMap); checkGL(); glBindTexture(GL_TEXTURE_2D, 0); checkGL(); //glEnable(GL_TEXTURE_2D); //checkGL(); } checkGL(); osystem_initBuffer(); checkGL(); GLuint vao; glGenVertexArrays(1, &vao); checkGL(); glBindVertexArray(vao); checkGL(); #endif } void osystem_setPalette(u8* palette) { memcpy(RGB_Pal, palette, 256 * 3); bgfx::updateTexture2D(g_paletteTexture, 0, 0, 0, 0, 3, 256, bgfx::copy(RGB_Pal, 256 * 3)); } void osystem_setPalette(palette_t* palette) { for (int i = 0; i < 256; i++) { for (int j = 0; j < 3; j++) { RGB_Pal[i * 3 + j] = palette->at(i)[j]; } } bgfx::updateTexture2D(g_paletteTexture, 0, 0, 0, 0, 3, 256, bgfx::copy(RGB_Pal, 256 * 3)); } struct s_vertexData { float positions[3]; float textures[2]; float color[4]; }; s_vertexData gVertexArray[1024 * 1024]; bgfx::ShaderHandle loadBgfxShader(const std::string& filename) { std::vector memBlob; FILE* fHandle = fopen(filename.c_str(), "rb"); if (fHandle == nullptr) return BGFX_INVALID_HANDLE; fseek(fHandle, 0, SEEK_END); u32 size = ftell(fHandle); fseek(fHandle, 0, SEEK_SET); memBlob.resize(size); fread(&memBlob[0], 1, size, fHandle); fclose(fHandle); bgfx::ShaderHandle handle = bgfx::createShader(bgfx::copy(&memBlob[0], size)); bgfx::setName(handle, filename.c_str()); return handle; } bgfx::ProgramHandle getBackgroundShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("background_vs", "background_ps"); } return programHandle; } bgfx::ProgramHandle getMaskBackgroundShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("maskBackground_vs", "maskBackground_ps"); } return programHandle; } bgfx::ProgramHandle getFlatShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("flat_vs", "flat_ps"); } return programHandle; } bgfx::ProgramHandle getNoiseShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("noise_vs", "noise_ps"); } return programHandle; } bgfx::ProgramHandle getRampShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("ramp_vs", "ramp_ps"); } return programHandle; } bgfx::ProgramHandle getSphereShader() { static bgfx::ProgramHandle programHandle = BGFX_INVALID_HANDLE; if (!bgfx::isValid(programHandle)) { programHandle = loadBgfxProgram("sphere_vs", "sphere_ps"); } return programHandle; } void osystem_drawBackground() { if (backgroundMode == backgroundModeEnum_2D) { bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .end(); bgfx::TransientVertexBuffer transientBuffer; bgfx::allocTransientVertexBuffer(&transientBuffer, 6, layout); struct sVertice { float position[3]; float texcoord[2]; }; sVertice* pVertices = (sVertice*)transientBuffer.data; float quadVertices[6 * 3]; float quadUV[6 * 2]; // 0 pVertices->position[0] = 0.f; pVertices->position[1] = 0.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 0.f; pVertices->texcoord[1] = 0.f; pVertices++; //2 pVertices->position[0] = 320.f; pVertices->position[1] = 200.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 1.f; pVertices->texcoord[1] = 1.f; pVertices++; //1 pVertices->position[0] = 320.f; pVertices->position[1] = 0.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 1.f; pVertices->texcoord[1] = 0.f; pVertices++; //------------------------ //3 pVertices->position[0] = 0.f; pVertices->position[1] = 0.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 0.f; pVertices->texcoord[1] = 0.f; pVertices++; //4 pVertices->position[0] = 0.f; pVertices->position[1] = 200.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 0.f; pVertices->texcoord[1] = 1.f; pVertices++; //5 pVertices->position[0] = 320.f; pVertices->position[1] = 200.f; pVertices->position[2] = 1000.f; pVertices->texcoord[0] = 1.f; pVertices->texcoord[1] = 1.f; pVertices++; static bgfx::UniformHandle backgroundTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(backgroundTextureUniform)) { backgroundTextureUniform = bgfx::createUniform("s_backgroundTexture", bgfx::UniformType::Sampler); } static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_MSAA ); bgfx::setVertexBuffer(0, &transientBuffer); bgfx::setTexture(0, backgroundTextureUniform, g_backgroundTexture); bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::submit(gameViewId, getBackgroundShader()); } } bool g_bgfxMainResourcesInitialized = false; bgfx::FrameBufferHandle fieldModelInspector_FB = BGFX_INVALID_HANDLE; bgfx::TextureHandle fieldModelInspector_Texture = BGFX_INVALID_HANDLE; bgfx::TextureHandle fieldModelInspector_Depth = BGFX_INVALID_HANDLE; void initBgfxMainResources() { // create background texture g_backgroundTexture = bgfx::createTexture2D(320, 200, false, 1, bgfx::TextureFormat::R8U); g_paletteTexture = bgfx::createTexture2D(3, 256, false, 1, bgfx::TextureFormat::R8U); } ImVec2 gameResolution = { 320, 200 }; void renderGameWindow() { if (ImGui::Begin("Game")) { if (bgfx::getCaps()->originBottomLeft) { ImGui::Image(fieldModelInspector_Texture, gameResolution, ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); } else { ImGui::Image(fieldModelInspector_Texture, gameResolution, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f)); } } ImGui::End(); } void osystem_startFrame() { if (!g_bgfxMainResourcesInitialized) { initBgfxMainResources(); g_bgfxMainResourcesInitialized = true; } static ImVec2 oldWindowSize = { -1,-1 }; if (debuggerVar_debugMenuDisplayed) { gameViewId = 1; if (ImGui::Begin("Game")) { ImVec2 currentWindowSize = ImGui::GetContentRegionAvail(); currentWindowSize[0] = std::max(currentWindowSize[0], 1); currentWindowSize[1] = std::max(currentWindowSize[1], 1); gameResolution = currentWindowSize; } else { gameResolution = { 320, 200 }; } ImGui::End(); if ((gameResolution[0] != oldWindowSize[0]) || (gameResolution[1] != oldWindowSize[1])) { oldWindowSize = gameResolution; if (bgfx::isValid(fieldModelInspector_FB)) { bgfx::destroy(fieldModelInspector_FB); } const uint64_t tsFlags = 0 //| BGFX_SAMPLER_MIN_POINT //| BGFX_SAMPLER_MAG_POINT //| BGFX_SAMPLER_MIP_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP ; fieldModelInspector_Texture = bgfx::createTexture2D(gameResolution[0], gameResolution[1], false, 0, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags); fieldModelInspector_Depth = bgfx::createTexture2D(gameResolution[0], gameResolution[1], false, 0, bgfx::TextureFormat::D24S8, BGFX_TEXTURE_RT | tsFlags); std::array attachements; attachements[0].init(fieldModelInspector_Texture); attachements[1].init(fieldModelInspector_Depth); fieldModelInspector_FB = bgfx::createFrameBuffer(2, &attachements[0], true); } bgfx::setViewFrameBuffer(gameViewId, fieldModelInspector_FB); bgfx::setViewRect(gameViewId, 0, 0, gameResolution[0], gameResolution[1]); } else { gameViewId = 0; gameResolution[0] = outputResolution[0]; gameResolution[1] = outputResolution[1]; bgfx::setViewFrameBuffer(gameViewId, BGFX_INVALID_HANDLE); //bind the backbuffer } { bgfx::setViewClear(gameViewId, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 255); bgfx::setViewName(gameViewId, "Game"); bgfx::setViewMode(gameViewId, bgfx::ViewMode::Sequential); bgfx::touch(gameViewId); } osystem_drawBackground(); } unsigned char frontBuffer[320 * 200]; unsigned char physicalScreen[320 * 200]; unsigned char physicalScreenRGB[320 * 200 * 3]; void osystem_CopyBlockPhys(unsigned char* videoBuffer, int left, int top, int right, int bottom) { unsigned char* out = physicalScreenRGB; unsigned char* in = (unsigned char*)&videoBuffer[0] + left + top * 320; int i; int j; while ((right - left) % 4) { right++; } while ((bottom - top) % 4) { bottom++; } for (i = top; i < bottom; i++) { in = (unsigned char*)&videoBuffer[0] + left + i * 320; unsigned char* out2 = physicalScreen + left + i * 320; for (j = left; j < right; j++) { unsigned char color = *(in++); *(out++) = RGB_Pal[color * 3]; *(out++) = RGB_Pal[color * 3 + 1]; *(out++) = RGB_Pal[color * 3 + 2]; *(out2++) = color; } } bgfx::updateTexture2D(g_backgroundTexture, 0, 0, 0, 0, 320, 200, bgfx::copy(physicalScreen, 320 * 200)); } void osystem_refreshFrontTextureBuffer() { unsigned char* out = physicalScreenRGB; unsigned char* in = physicalScreen; int i; int j; for (i = 0; i < 200 * 320; i++) { unsigned char color = *(in++); *(out++) = RGB_Pal[color * 3]; *(out++) = RGB_Pal[color * 3 + 1]; *(out++) = RGB_Pal[color * 3 + 2]; } bgfx::updateTexture2D(g_backgroundTexture, 0, 0, 0, 0, 320, 200, bgfx::copy(physicalScreen, 320 * 200)); } void osystem_initBuffer() { memset(backBuffer, 0x0, 512 * 256 * 3); } void gameScreenToViewport(float* X, float* Y) { (*X) = (*X) * g_screenWidth / 320.f; (*Y) = (*Y) * g_screenHeight / 200.f; (*Y) = g_screenHeight - (*Y); } void osystem_setClip(float left, float top, float right, float bottom) { float x1 = left - 1; float y1 = bottom + 1; float x2 = right + 1; float y2 = top - 1; gameScreenToViewport(&x1, &y1); gameScreenToViewport(&x2, &y2); float width = x2 - x1; float height = y2 - y1; float currentScissor[4]; currentScissor[0] = ((left - 1) / 320.f) * gameResolution[0]; currentScissor[1] = ((top - 1) / 200.f) * gameResolution[1]; currentScissor[2] = ((right - left + 2) / 320.f) * gameResolution[0]; currentScissor[3] = ((bottom - top + 2) / 200.f) * gameResolution[1]; currentScissor[0] = std::max(currentScissor[0], 0); currentScissor[1] = std::max(currentScissor[1], 0); bgfx::setScissor(currentScissor[0], currentScissor[1], currentScissor[2], currentScissor[3]); } void osystem_clearClip() { bgfx::setScissor(0, 0, gameResolution[0], gameResolution[1]); } void osystem_stopFrame() { } void osystem_startModelRender() { } void osystem_stopModelRender() { osystem_flushPendingPrimitives(); } void osystem_flushPendingPrimitives() { if (numUsedFlatVertices) { bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8) .end(); bgfx::TransientVertexBuffer transientBuffer; bgfx::allocTransientVertexBuffer(&transientBuffer, numUsedFlatVertices, layout); memcpy(transientBuffer.data, &flatVertices[0], sizeof(polyVertex) * numUsedFlatVertices); bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LEQUAL | BGFX_STATE_MSAA ); static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::setVertexBuffer(0, &transientBuffer); bgfx::submit(gameViewId, getFlatShader()); } if (numUsedNoiseVertices) { bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8) .end(); bgfx::TransientVertexBuffer transientBuffer; bgfx::allocTransientVertexBuffer(&transientBuffer, numUsedNoiseVertices, layout); memcpy(transientBuffer.data, &noiseVertices[0], sizeof(polyVertex) * numUsedNoiseVertices); bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LEQUAL | BGFX_STATE_MSAA ); static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::setVertexBuffer(0, &transientBuffer); bgfx::submit(gameViewId, getNoiseShader()); } if (numUsedRampVertices) { bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8) .end(); bgfx::TransientVertexBuffer transientBuffer; bgfx::allocTransientVertexBuffer(&transientBuffer, numUsedRampVertices, layout); memcpy(transientBuffer.data, &rampVertices[0], sizeof(polyVertex) * numUsedRampVertices); bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LEQUAL | BGFX_STATE_MSAA ); static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::setVertexBuffer(0, &transientBuffer); bgfx::submit(gameViewId, getRampShader()); } if(numUsedSpheres) { bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord1, 4, bgfx::AttribType::Float) .end(); bgfx::TransientVertexBuffer transientBuffer; bgfx::allocTransientVertexBuffer(&transientBuffer, numUsedSpheres, layout); memcpy(transientBuffer.data, &sphereVertices[0], sizeof(sphereVertex)* numUsedSpheres); bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LEQUAL | BGFX_STATE_MSAA ); static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::setVertexBuffer(0, &transientBuffer); bgfx::submit(gameViewId, getSphereShader()); } #if 0 if (numUsedTransparentVertices) { /* glEnable(GL_BLEND); checkGL(); glVertexPointer(3, GL_FLOAT, sizeof(polyVertex), &transparentVertices->X); checkGL(); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(polyVertex), &transparentVertices->R); checkGL(); glDrawArrays(GL_TRIANGLES, 0, numUsedTransparentVertices); checkGL(); glDisable(GL_BLEND); checkGL(); */ } #endif numUsedFlatVertices = 0; numUsedNoiseVertices = 0; numUsedRampVertices = 0; numUsedSpheres = 0; numUsedTransparentVertices = 0; } void osystem_fillPoly(float* buffer, int numPoint, unsigned char color, u8 polyType) { #define MAX_POINTS_PER_POLY 50 float UVArray[MAX_POINTS_PER_POLY]; assert(numPoint < MAX_POINTS_PER_POLY); // compute the polygon bounding box float polyMinX = 320.f; float polyMaxX = 0.f; float polyMinY = 200.f; float polyMaxY = 0.f; for (int i = 0; i < numPoint; i++) { float X = buffer[3 * i + 0]; float Y = buffer[3 * i + 1]; if (X > polyMaxX) polyMaxX = X; if (X < polyMinX) polyMinX = X; if (Y > polyMaxY) polyMaxY = Y; if (Y < polyMinY) polyMinY = Y; } float polyWidth = polyMaxX - polyMinX; float polyHeight = polyMaxY - polyMinY; if (polyWidth <= 0.f) polyWidth = 1; if (polyHeight <= 0.f) polyHeight = 1; switch (polyType) { default: case 0: // flat (triste) { polyVertex* pVertex = &flatVertices[numUsedFlatVertices]; numUsedFlatVertices += (numPoint - 2) * 3; assert(numUsedFlatVertices < NUM_MAX_FLAT_VERTICES); for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; int bank = (color & 0xF0) >> 4; int startColor = color & 0xF; float colorf = startColor; pVertex->U = colorf / 15.f; pVertex->V = bank / 15.f; pVertex++; } break; } case 1: // dither (pierre/tele) { polyVertex* pVertex = &noiseVertices[numUsedNoiseVertices]; numUsedNoiseVertices += (numPoint - 2) * 3; assert(numUsedNoiseVertices < NUM_MAX_NOISE_VERTICES); for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; pVertex->U = (pVertex->X / 320.f) * 50.f + polyMinX * 1.2f + polyMaxX; pVertex->V = (pVertex->Y / 200.f) * 50.f + polyMinY * 0.7f + polyMaxY; int bank = (color & 0xF0) >> 4; int startColor = color & 0xF; float colorf = startColor; pVertex->U = colorf / 15.f; pVertex->V = bank / 15.f; pVertex++; } break; } case 2: // trans { polyVertex* pVertex = &transparentVertices[numUsedTransparentVertices]; numUsedTransparentVertices += (numPoint - 2) * 3; assert(numUsedTransparentVertices < NUM_MAX_TRANSPARENT_VERTICES); for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; pVertex->R = RGB_Pal[color * 3]; pVertex->G = RGB_Pal[color * 3 + 1]; pVertex->B = RGB_Pal[color * 3 + 2]; pVertex->A = 128; pVertex++; } break; } case 4: // copper (ramps top to bottom) case 5: // copper2 (ramps top to bottom, 2 scanline per color) { polyVertex* pVertex = &rampVertices[numUsedRampVertices]; numUsedRampVertices += (numPoint - 2) * 3; assert(numUsedRampVertices < NUM_MAX_RAMP_VERTICES); int bank = (color & 0xF0) >> 4; int startColor = color & 0xF; float colorStep = 1; // TODO: this should be the scanline ratio for the current resolution to original resolution if (polyType == 5) { colorStep *= 0.5; // to stretch the ramp by 2 for copper2 } for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; float colorf = startColor + colorStep * (pVertex->Y - polyMinY); pVertex->U = colorf / 15.f; pVertex->V = bank / 15.f; pVertex++; } break; } case 3: // marbre (ramp left to right) { polyVertex* pVertex = &rampVertices[numUsedRampVertices]; numUsedRampVertices += (numPoint - 2) * 3; assert(numUsedRampVertices < NUM_MAX_RAMP_VERTICES); float colorStep = 15.f / polyWidth; int bank = (color & 0xF0) >> 4; int startColor = color & 0xF; assert(startColor == 0); for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; float colorf = startColor + colorStep * (pVertex->X - polyMinX); pVertex->U = colorf / 15.f; pVertex->V = bank / 15.f; pVertex++; } break; } case 6: // marbre2 (ramp right to left) { polyVertex* pVertex = &rampVertices[numUsedRampVertices]; numUsedRampVertices += (numPoint - 2) * 3; assert(numUsedRampVertices < NUM_MAX_RAMP_VERTICES); float colorStep = 15.f / polyWidth; int bank = (color & 0xF0) >> 4; int startColor = color & 0xF; assert(startColor == 0); for (int i = 0; i < numPoint; i++) { if (i >= 3) { memcpy(pVertex, &pVertex[-3], sizeof(polyVertex)); pVertex++; memcpy(pVertex, &pVertex[-2], sizeof(polyVertex)); pVertex++; } pVertex->X = buffer[i * 3 + 0]; pVertex->Y = buffer[i * 3 + 1]; pVertex->Z = buffer[i * 3 + 2]; float colorf = startColor + colorStep * (pVertex->X - polyMinX); pVertex->U = 1.f - colorf / 15.f; pVertex->V = bank / 15.f; pVertex++; } break; } } } void osystem_draw3dLine(float x1, float y1, float z1, float x2, float y2, float z2, unsigned char color) { #if 0 GLfloat lineVertices[2 * 3]; GLubyte lineColor[2 * 4]; for (int i = 0; i < 2; i++) { lineColor[4 * i + 0] = RGB_Pal[color * 3 + 0]; lineColor[4 * i + 1] = RGB_Pal[color * 3 + 1]; lineColor[4 * i + 2] = RGB_Pal[color * 3 + 2]; lineColor[4 * i + 3] = 255; } lineVertices[0] = x1; lineVertices[1] = y1; lineVertices[2] = z1; lineVertices[3] = x2; lineVertices[4] = y2; lineVertices[5] = z2; static GLuint shaderprogram = 0; static GLuint vertexp = 0; static GLuint colorp = 0; if (shaderprogram == 0) { shaderprogram = compileShader(flatQuadVS, flatQuadPS); vertexp = glGetAttribLocation(shaderprogram, (const GLchar*)"in_Position"); colorp = glGetAttribLocation(shaderprogram, (const GLchar*)"in_Color"); } glUseProgram(shaderprogram); static GLuint vbo = 0; if (vbo == 0) { glGenBuffers(1, &vbo); } for (int i = 0; i < 2; i++) { gVertexArray[i].positions[0] = lineVertices[i * 3 + 0]; gVertexArray[i].positions[1] = lineVertices[i * 3 + 1]; gVertexArray[i].positions[2] = lineVertices[i * 3 + 2]; gVertexArray[i].color[0] = lineColor[i * 4 + 0] / 255.f; gVertexArray[i].color[1] = lineColor[i * 4 + 1] / 255.f; gVertexArray[i].color[2] = lineColor[i * 4 + 2] / 255.f; gVertexArray[i].color[3] = lineColor[i * 4 + 3] / 255.f; } glBindBuffer(GL_ARRAY_BUFFER, vbo); checkGL(); glBufferData(GL_ARRAY_BUFFER, sizeof(s_vertexData) * 2, &gVertexArray[0], GL_STATIC_DRAW); checkGL(); glVertexAttribPointer(vertexp, 3, GL_FLOAT, GL_FALSE, sizeof(s_vertexData), (void*)&((s_vertexData*)NULL)->positions); checkGL(); glEnableVertexAttribArray(vertexp); checkGL(); if (colorp != -1) { glVertexAttribPointer(colorp, 4, GL_FLOAT, GL_FALSE, sizeof(s_vertexData), (void*)&((s_vertexData*)NULL)->color); glEnableVertexAttribArray(colorp); } glDrawArrays(GL_LINE_LOOP, 0, 2); checkGL(); checkGL(); #endif } void osystem_draw3dQuad(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, unsigned char color, int transparency) { float lineVertices[4 * 3]; unsigned char lineColor1[4 * 4]; unsigned char lineColor2[4 * 4]; for (int i = 0; i < 4; i++) { lineColor1[i * 4 + 0] = RGB_Pal[(color + 3) * 3]; lineColor1[i * 4 + 1] = RGB_Pal[(color + 3) * 3 + 1]; lineColor1[i * 4 + 2] = RGB_Pal[(color + 3) * 3 + 2]; lineColor1[i * 4 + 3] = 255; lineColor2[i * 4 + 0] = RGB_Pal[color * 3]; lineColor2[i * 4 + 1] = RGB_Pal[color * 3 + 1]; lineColor2[i * 4 + 2] = RGB_Pal[color * 3 + 2]; lineColor2[i * 4 + 3] = 255; } lineVertices[0] = x1; lineVertices[1] = y1; lineVertices[2] = z1; lineVertices[3] = x2; lineVertices[4] = y2; lineVertices[5] = z2; lineVertices[6] = x4; lineVertices[7] = y4; lineVertices[8] = z4; lineVertices[9] = x3; lineVertices[10] = y3; lineVertices[11] = z3; osystem_draw3dLine(x1, y1, z1, x2, y2, z2, color); osystem_draw3dLine(x2, y2, z2, x3, y3, z3, color); osystem_draw3dLine(x3, y3, z3, x4, y4, z4, color); osystem_draw3dLine(x4, y4, z4, x1, y1, z1, color); //glEnable(GL_DEPTH_TEST); //glDisable(GL_BLEND); /*glColor4ub(1.f, 1.f, 1.f, 1.f); glVertexPointer(3, GL_FLOAT, 0, lineVertices); glColorPointer(4, GL_UNSIGNED_BYTE, 0, lineColor1); glDrawArrays(GL_LINE_LOOP, 0, 4); checkGL();*/ /* { checkGL(); glVertexPointer(3, GL_FLOAT, 0, lineVertices); glColorPointer(4, GL_UNSIGNED_BYTE, 0, lineColor2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGL(); } */ } void osystem_drawSphere(float X, float Y, float Z, u8 color, u8 material, float size) { osystem_drawPoint(X, Y, Z, color, material, size); } void osystem_drawPoint(float X, float Y, float Z, u8 color, u8 material, float size) { std::array corners; corners[0].X = X + size; corners[0].Y = Y + size; corners[0].Z = Z; corners[1].X = X + size; corners[1].Y = Y - size; corners[1].Z = Z; corners[2].X = X - size; corners[2].Y = Y - size; corners[2].Z = Z; corners[3].X = X - size; corners[3].Y = Y + size; corners[3].Z = Z; std::array mapping = { { 0,1,2, 0,2,3 } }; for(int i=0; i< mapping.size(); i++) { sphereVertex* pVertex = &sphereVertices[numUsedSpheres]; numUsedSpheres++; assert(numUsedSpheres < NUM_MAX_SPHERES_VERTICES); pVertex->X = corners[mapping[i]].X; pVertex->Y = corners[mapping[i]].Y; pVertex->Z = corners[mapping[i]].Z; pVertex->U = (color & 0xF) / 15.f; pVertex->V = ((color & 0xF0) >> 4) / 15.f; pVertex->size = size; pVertex->centerX = X; pVertex->centerY = Y; pVertex->material = material; } } void osystem_flip(unsigned char* videoBuffer) { osystem_flushPendingPrimitives(); } void osystem_createMask(const std::array& mask, int roomId, int maskId, unsigned char* refImage, int maskX1, int maskY1, int maskX2, int maskY2) { if (maskTextures.size() < roomId + 1) { maskTextures.resize(roomId + 1); } if (maskTextures[roomId].size() < maskId + 1) { maskTextures[roomId].resize(maskId + 1); } if (bgfx::isValid(maskTextures[roomId][maskId].maskTexture)) { bgfx::destroy(maskTextures[roomId][maskId].maskTexture); maskTextures[roomId][maskId].maskTexture = BGFX_INVALID_HANDLE; } if (bgfx::isValid(maskTextures[roomId][maskId].vertexBuffer)) { bgfx::destroy(maskTextures[roomId][maskId].vertexBuffer); maskTextures[roomId][maskId].vertexBuffer = BGFX_INVALID_HANDLE; } maskTextures[roomId][maskId].maskTexture = bgfx::createTexture2D(320, 200, false, 1, bgfx::TextureFormat::R8U, 0, bgfx::copy(&mask[0], 320 * 200)); maskTextures[roomId][maskId].maskX1 = maskX1; maskTextures[roomId][maskId].maskX2 = maskX2 + 1; maskTextures[roomId][maskId].maskY1 = maskY1; maskTextures[roomId][maskId].maskY2 = maskY2 + 1; bgfx::VertexLayout layout; layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .end(); float X1 = maskTextures[roomId][maskId].maskX1; float X2 = maskTextures[roomId][maskId].maskX2; float Y1 = maskTextures[roomId][maskId].maskY1; float Y2 = maskTextures[roomId][maskId].maskY2; float maskZ = 0.f; struct sVertice { float position[3]; float texcoord[2]; } vertexBuffer[4]; sVertice* pVertices = vertexBuffer; pVertices->position[0] = X1; pVertices->position[1] = Y2; pVertices->position[2] = maskZ; pVertices->texcoord[0] = X1 / 320.f; pVertices->texcoord[1] = Y2 / 200.f; pVertices++; pVertices->position[0] = X1; pVertices->position[1] = Y1; pVertices->position[2] = maskZ; pVertices->texcoord[0] = X1 / 320.f; pVertices->texcoord[1] = Y1 / 200.f; pVertices++; pVertices->position[0] = X2; pVertices->position[1] = Y2; pVertices->position[2] = maskZ; pVertices->texcoord[0] = X2 / 320.f; pVertices->texcoord[1] = Y2 / 200.f; pVertices++; pVertices->position[0] = X2; pVertices->position[1] = Y1; pVertices->position[2] = maskZ; pVertices->texcoord[0] = X2 / 320.f; pVertices->texcoord[1] = Y1 / 200.f; pVertices++; maskTextures[roomId][maskId].vertexBuffer = bgfx::createVertexBuffer(bgfx::copy(vertexBuffer, sizeof(vertexBuffer)), layout); } void osystem_drawMask(int roomId, int maskId) { if (g_gameId == TIMEGATE) return; if (!bgfx::isValid(maskTextures[roomId][maskId].maskTexture)) return; if (!bgfx::isValid(maskTextures[roomId][maskId].vertexBuffer)) return; #ifdef FITD_DEBUGGER if (backgroundMode != backgroundModeEnum_2D) return; #endif static bgfx::UniformHandle backgroundTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(backgroundTextureUniform)) { backgroundTextureUniform = bgfx::createUniform("s_backgroundTexture", bgfx::UniformType::Sampler); } static bgfx::UniformHandle paletteTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(paletteTextureUniform)) { paletteTextureUniform = bgfx::createUniform("s_paletteTexture", bgfx::UniformType::Sampler); } static bgfx::UniformHandle maskTextureUniform = BGFX_INVALID_HANDLE; if (!bgfx::isValid(maskTextureUniform)) { maskTextureUniform = bgfx::createUniform("s_maskTexture", bgfx::UniformType::Sampler); } bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_MSAA | BGFX_STATE_PT_TRISTRIP ); bgfx::setVertexBuffer(0, maskTextures[roomId][maskId].vertexBuffer); bgfx::setTexture(2, backgroundTextureUniform, g_backgroundTexture); bgfx::setTexture(1, paletteTextureUniform, g_paletteTexture); bgfx::setTexture(0, maskTextureUniform, maskTextures[roomId][maskId].maskTexture); bgfx::submit(gameViewId, getMaskBackgroundShader()); }