// Copyright (C) 2003-2009 Dolphin Project. // 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, version 2.0. // 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 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ #include "Common.h" #include "MemoryUtil.h" #include #include "BPMemLoader.h" #include "HwRasterizer.h" #include "GLUtil.h" #include "NativeVertexFormat.h" #include "DebugUtil.h" #define TEMP_SIZE (1024*1024*4) namespace HwRasterizer { float efbHalfWidth; float efbHalfHeight; float texWidth; float texHeight; bool hasTexture; u8 *temp; void Init() { efbHalfWidth = EFB_WIDTH / 2.0f; efbHalfHeight = 480 / 2.0f; temp = (u8*)AllocateMemoryPages(TEMP_SIZE); } void LoadTexture() { FourTexUnits &texUnit = bpmem.tex[0]; u32 imageAddr = texUnit.texImage3[0].image_base; TexCacheEntry &cacheEntry = textures[imageAddr]; cacheEntry.Update(); texWidth = (float)(bpmem.texcoords[0].s.scale_minus_1 + 1); texHeight = (float)(bpmem.texcoords[0].t.scale_minus_1 + 1); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cacheEntry.texture); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST); } void BeginTriangles() { // disabling depth test sometimes allows more things to be visible glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); hasTexture = bpmem.tevorders[0].enable0; if (hasTexture) LoadTexture(); } void EndTriangles() { glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); } void DrawColorVertex(OutputVertexData *v) { glColor3ub(v->color[0][0], v->color[0][1], v->color[0][2]); glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z); } void DrawTextureVertex(OutputVertexData *v) { glTexCoord2f(v->texCoords[0].x * texWidth, v->texCoords[0].y * texHeight); glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z); } void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) { glBegin(GL_TRIANGLES); if (hasTexture) { DrawTextureVertex(v0); DrawTextureVertex(v1); DrawTextureVertex(v2); } else { DrawColorVertex(v0); DrawColorVertex(v1); DrawColorVertex(v2); } glEnd(); } void Clear() { u8 r = (bpmem.clearcolorAR & 0x00ff); u8 g = (bpmem.clearcolorGB & 0xff00) >> 8; u8 b = (bpmem.clearcolorGB & 0x00ff); u8 a = (bpmem.clearcolorAR & 0xff00) >> 8; GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f; GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight; GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f; GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight; GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff; glBegin(GL_QUADS); glColor4ub(r, g, b, a); glVertex3f(left, top, depth); glColor4ub(r, g, b, a); glVertex3f(right, top, depth); glColor4ub(r, g, b, a); glVertex3f(right, bottom, depth); glColor4ub(r, g, b, a); glVertex3f(left, bottom, depth); glEnd(); } TexCacheEntry::TexCacheEntry() { Create(); } void TexCacheEntry::Create() { FourTexUnits &texUnit = bpmem.tex[0]; texImage0.hex = texUnit.texImage0[0].hex; texImage1.hex = texUnit.texImage1[0].hex; texImage2.hex = texUnit.texImage2[0].hex; texImage3.hex = texUnit.texImage3[0].hex; texTlut.hex = texUnit.texTlut[0].hex; int width = texImage0.width; int height = texImage0.height; DebugUtil::GetTextureBGRA(temp, 0, 0, width, height); glGenTextures(1, (GLuint *)&texture); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp); } void TexCacheEntry::Destroy() { if (texture == 0) return; glDeleteTextures(1, &texture); texture = 0; } void TexCacheEntry::Update() { FourTexUnits &texUnit = bpmem.tex[0]; // extra checks cause textures to be reloaded much more if (texUnit.texImage0[0].hex != texImage0.hex || //texUnit.texImage1[0].hex != texImage1.hex || //texUnit.texImage2[0].hex != texImage2.hex || texUnit.texImage3[0].hex != texImage3.hex || texUnit.texTlut[0].hex != texTlut.hex) { Destroy(); Create(); } } }