Initial commit
This commit is contained in:
23
graphics/tinygl/LICENSE
Normal file
23
graphics/tinygl/LICENSE
Normal file
@@ -0,0 +1,23 @@
|
||||
NOTE: This implementation of TinyGL contains additional code and
|
||||
modifications added only for ScummVM project.
|
||||
Look into the source code file "Changelog" for more info.
|
||||
|
||||
Copyright (c) 1997-2022 Fabrice Bellard
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
1121
graphics/tinygl/api.cpp
Normal file
1121
graphics/tinygl/api.cpp
Normal file
File diff suppressed because it is too large
Load Diff
387
graphics/tinygl/arrays.cpp
Normal file
387
graphics/tinygl/arrays.cpp
Normal file
@@ -0,0 +1,387 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
#define NORLALIZE_SBYTE(n) ( ( (float) n * 2.0f + 1.0f ) / 255.0f )
|
||||
#define NORLALIZE_UBYTE(n) ( (float) n / 255.0f )
|
||||
|
||||
#define NORLALIZE_SSHORT(n) ( ( (float) n * 2.0f + 1.0f ) / 65535.0f )
|
||||
#define NORLALIZE_USHORT(n) ( (float) n / 65535.0f )
|
||||
|
||||
#define NORLALIZE_SINT(n) ( ( (float) n * 2.0f + 1.0f ) / 4294967295.0f )
|
||||
#define NORLALIZE_UINT(n) ( (float) n / 4294967295.0f )
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopArrayElement(GLParam *param) {
|
||||
int offset;
|
||||
int states = client_states;
|
||||
int idx = param[1].i;
|
||||
|
||||
if (states & COLOR_ARRAY) {
|
||||
GLParam p[5];
|
||||
int size = color_array_size;
|
||||
offset = idx * color_array_stride;
|
||||
switch (color_array_type) {
|
||||
case TGL_UNSIGNED_BYTE: {
|
||||
TGLubyte *array = (TGLubyte *)color_array + offset;
|
||||
p[1].f = NORLALIZE_UBYTE(array[0]);
|
||||
p[2].f = NORLALIZE_UBYTE(array[1]);
|
||||
p[3].f = NORLALIZE_UBYTE(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_UBYTE(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_BYTE: {
|
||||
TGLbyte *array = (TGLbyte *)color_array + offset;
|
||||
p[1].f = NORLALIZE_SBYTE(array[0]);
|
||||
p[2].f = NORLALIZE_SBYTE(array[1]);
|
||||
p[3].f = NORLALIZE_SBYTE(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_SBYTE(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_UNSIGNED_INT: {
|
||||
TGLuint *array = (TGLuint *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = NORLALIZE_UINT(array[0]);
|
||||
p[2].f = NORLALIZE_UINT(array[1]);
|
||||
p[3].f = NORLALIZE_UINT(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_UINT(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_INT: {
|
||||
TGLint *array = (TGLint *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = NORLALIZE_SINT(array[0]);
|
||||
p[2].f = NORLALIZE_SINT(array[1]);
|
||||
p[3].f = NORLALIZE_SINT(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_SINT(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_UNSIGNED_SHORT: {
|
||||
TGLushort *array = (TGLushort *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = NORLALIZE_USHORT(array[0]);
|
||||
p[2].f = NORLALIZE_USHORT(array[1]);
|
||||
p[3].f = NORLALIZE_USHORT(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_USHORT(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_SHORT: {
|
||||
TGLshort *array = (TGLshort *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = NORLALIZE_SSHORT(array[0]);
|
||||
p[2].f = NORLALIZE_SSHORT(array[1]);
|
||||
p[3].f = NORLALIZE_SSHORT(array[2]);
|
||||
p[4].f = size > 3 ? NORLALIZE_SSHORT(array[3]) : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_FLOAT: {
|
||||
TGLfloat *array = (TGLfloat *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = array[2];
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_DOUBLE: {
|
||||
TGLdouble *array = (TGLdouble *)((TGLbyte *)color_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = array[2];
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
glopColor(p);
|
||||
}
|
||||
if (states & NORMAL_ARRAY) {
|
||||
offset = idx * normal_array_stride;
|
||||
current_normal.W = 0.0f;
|
||||
switch (normal_array_type) {
|
||||
case TGL_FLOAT: {
|
||||
TGLfloat *array = (TGLfloat *)((TGLbyte *)normal_array + offset);
|
||||
current_normal.X = array[0];
|
||||
current_normal.Y = array[1];
|
||||
current_normal.Z = array[2];
|
||||
break;
|
||||
}
|
||||
case TGL_DOUBLE: {
|
||||
TGLdouble *array = (TGLdouble *)((TGLbyte *)normal_array + offset);
|
||||
current_normal.X = array[0];
|
||||
current_normal.Y = array[1];
|
||||
current_normal.Z = array[2];
|
||||
break;
|
||||
}
|
||||
case TGL_INT: {
|
||||
TGLint *array = (TGLint *)((TGLbyte *)normal_array + offset);
|
||||
current_normal.X = NORLALIZE_SINT(array[0]);
|
||||
current_normal.Y = NORLALIZE_SINT(array[1]);
|
||||
current_normal.Z = NORLALIZE_SINT(array[2]);
|
||||
break;
|
||||
}
|
||||
case TGL_SHORT: {
|
||||
TGLshort *array = (TGLshort *)((TGLbyte *)normal_array + offset);
|
||||
current_normal.X = NORLALIZE_SSHORT(array[0]);
|
||||
current_normal.Y = NORLALIZE_SSHORT(array[1]);
|
||||
current_normal.Z = NORLALIZE_SSHORT(array[2]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
if (states & TEXCOORD_ARRAY) {
|
||||
int size = texcoord_array_size;
|
||||
offset = idx * texcoord_array_stride;
|
||||
switch (texcoord_array_type) {
|
||||
case TGL_FLOAT: {
|
||||
TGLfloat *array = (TGLfloat *)((TGLbyte *)texcoord_array + offset);
|
||||
current_tex_coord.X = array[0];
|
||||
current_tex_coord.Y = array[1];
|
||||
current_tex_coord.Z = size > 2 ? array[2] : 0.0f;
|
||||
current_tex_coord.W = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_DOUBLE: {
|
||||
TGLdouble *array = (TGLdouble *)((TGLbyte *)texcoord_array + offset);
|
||||
current_tex_coord.X = array[0];
|
||||
current_tex_coord.Y = array[1];
|
||||
current_tex_coord.Z = size > 2 ? array[2] : 0.0f;
|
||||
current_tex_coord.W = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_INT: {
|
||||
TGLint *array = (TGLint *)((TGLbyte *)texcoord_array + offset);
|
||||
current_tex_coord.X = array[0];
|
||||
current_tex_coord.Y = array[1];
|
||||
current_tex_coord.Z = size > 2 ? array[2] : 0.0f;
|
||||
current_tex_coord.W = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_SHORT: {
|
||||
TGLshort *array = (TGLshort *)((TGLbyte *)texcoord_array + offset);
|
||||
current_tex_coord.X = array[0];
|
||||
current_tex_coord.Y = array[1];
|
||||
current_tex_coord.Z = size > 2 ? array[2] : 0.0f;
|
||||
current_tex_coord.W = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
if (states & VERTEX_ARRAY) {
|
||||
GLParam p[5];
|
||||
int size = vertex_array_size;
|
||||
offset = idx * vertex_array_stride;
|
||||
switch (vertex_array_type) {
|
||||
case TGL_FLOAT: {
|
||||
TGLfloat *array = (TGLfloat *)((TGLbyte *)vertex_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = size > 2 ? array[2] : 0.0f;
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_DOUBLE: {
|
||||
TGLdouble *array = (TGLdouble *)((TGLbyte *)vertex_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = size > 2 ? array[2] : 0.0f;
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_INT: {
|
||||
TGLint *array = (TGLint *)((TGLbyte *)vertex_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = size > 2 ? array[2] : 0.0f;
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
case TGL_SHORT: {
|
||||
TGLshort *array = (TGLshort *)((TGLbyte *)vertex_array + offset);
|
||||
p[1].f = array[0];
|
||||
p[2].f = array[1];
|
||||
p[3].f = size > 2 ? array[2] : 0.0f;
|
||||
p[4].f = size > 3 ? array[3] : 1.0f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
glopVertex(p);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopDrawArrays(GLParam *p) {
|
||||
GLParam array_element[2];
|
||||
GLParam begin[2];
|
||||
|
||||
begin[1].i = p[1].i;
|
||||
glopBegin(begin);
|
||||
for (int i = 0; i < p[3].i; i++) {
|
||||
array_element[1].i = p[2].i + i;
|
||||
glopArrayElement(array_element);
|
||||
}
|
||||
glopEnd(nullptr);
|
||||
}
|
||||
|
||||
void GLContext::glopDrawElements(GLParam *p) {
|
||||
GLParam array_element[2];
|
||||
void *indices;
|
||||
GLParam begin[2];
|
||||
|
||||
indices = (char *)p[4].p;
|
||||
begin[1].i = p[1].i;
|
||||
|
||||
glopBegin(begin);
|
||||
for (int i = 0; i < p[2].i; i++) {
|
||||
switch (p[3].i) {
|
||||
case TGL_UNSIGNED_BYTE:
|
||||
array_element[1].i = ((TGLbyte *)indices)[i];
|
||||
break;
|
||||
case TGL_UNSIGNED_SHORT:
|
||||
array_element[1].i = ((TGLshort *)indices)[i];
|
||||
break;
|
||||
case TGL_UNSIGNED_INT:
|
||||
array_element[1].i = ((TGLint *)indices)[i];
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
glopArrayElement(array_element);
|
||||
}
|
||||
glopEnd(nullptr);
|
||||
}
|
||||
|
||||
void GLContext::gl_EnableClientState(GLParam *p) {
|
||||
client_states |= p[1].i;
|
||||
}
|
||||
|
||||
void GLContext::gl_DisableClientState(GLParam *p) {
|
||||
client_states &= p[1].i;
|
||||
}
|
||||
|
||||
void GLContext::gl_VertexPointer(GLParam *p) {
|
||||
vertex_array_size = p[1].i;
|
||||
vertex_array_type = p[2].i;
|
||||
vertex_array = p[4].p;
|
||||
switch (vertex_array_type) {
|
||||
case TGL_FLOAT:
|
||||
vertex_array_stride = p[3].i != 0 ? p[3].i : vertex_array_size * sizeof(TGLfloat);
|
||||
break;
|
||||
case TGL_DOUBLE:
|
||||
vertex_array_stride = p[3].i != 0 ? p[3].i : vertex_array_size * sizeof(TGLdouble);
|
||||
break;
|
||||
case TGL_INT:
|
||||
vertex_array_stride = p[3].i != 0 ? p[3].i : vertex_array_size * sizeof(TGLint);
|
||||
break;
|
||||
case TGL_SHORT:
|
||||
vertex_array_stride = p[3].i != 0 ? p[3].i : vertex_array_size * sizeof(TGLshort);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_ColorPointer(GLParam *p) {
|
||||
color_array_size = p[1].i;
|
||||
color_array_type = p[2].i;
|
||||
color_array = p[4].p;
|
||||
switch (color_array_type) {
|
||||
case TGL_BYTE:
|
||||
case TGL_UNSIGNED_BYTE:
|
||||
color_array_stride = p[3].i != 0 ? p[3].i : color_array_stride * sizeof(TGLbyte);
|
||||
break;
|
||||
case TGL_SHORT:
|
||||
case TGL_UNSIGNED_SHORT:
|
||||
color_array_stride = p[3].i != 0 ? p[3].i : color_array_stride * sizeof(TGLshort);
|
||||
break;
|
||||
case TGL_INT:
|
||||
case TGL_UNSIGNED_INT:
|
||||
color_array_stride = p[3].i != 0 ? p[3].i : color_array_stride * sizeof(TGLint);
|
||||
break;
|
||||
case TGL_FLOAT:
|
||||
color_array_stride = p[3].i != 0 ? p[3].i : color_array_stride * sizeof(TGLfloat);
|
||||
break;
|
||||
case TGL_DOUBLE:
|
||||
color_array_stride = p[3].i != 0 ? p[3].i : color_array_stride * sizeof(TGLdouble);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_NormalPointer(GLParam *p) {
|
||||
normal_array_type = p[1].i;
|
||||
normal_array = p[3].p;
|
||||
switch (p[1].i) {
|
||||
case TGL_FLOAT:
|
||||
normal_array_stride = p[2].i != 0 ? p[2].i : 3 * sizeof(TGLfloat);
|
||||
break;
|
||||
case TGL_DOUBLE:
|
||||
normal_array_stride = p[2].i != 0 ? p[2].i : 3 * sizeof(TGLdouble);
|
||||
break;
|
||||
case TGL_INT:
|
||||
normal_array_stride = p[2].i != 0 ? p[2].i : 3 * sizeof(TGLint);
|
||||
break;
|
||||
case TGL_SHORT:
|
||||
normal_array_stride = p[2].i != 0 ? p[2].i : 3 * sizeof(TGLshort);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_TexCoordPointer(GLParam *p) {
|
||||
texcoord_array_size = p[1].i;
|
||||
texcoord_array_type = p[2].i;
|
||||
texcoord_array = p[4].p;
|
||||
switch (texcoord_array_type) {
|
||||
case TGL_FLOAT:
|
||||
texcoord_array_stride = p[3].i != 0 ? p[3].i : texcoord_array_size * sizeof(TGLfloat);
|
||||
break;
|
||||
case TGL_DOUBLE:
|
||||
texcoord_array_stride = p[3].i != 0 ? p[3].i : texcoord_array_size * sizeof(TGLdouble);
|
||||
break;
|
||||
case TGL_INT:
|
||||
texcoord_array_stride = p[3].i != 0 ? p[3].i : texcoord_array_size * sizeof(TGLint);
|
||||
break;
|
||||
case TGL_SHORT:
|
||||
texcoord_array_stride = p[3].i != 0 ? p[3].i : texcoord_array_size * sizeof(TGLshort);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
58
graphics/tinygl/clear.cpp
Normal file
58
graphics/tinygl/clear.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopClearColor(GLParam *p) {
|
||||
clear_color = Vector4(p[1].f, p[2].f, p[3].f, p[4].f);
|
||||
}
|
||||
|
||||
void GLContext::glopClearDepth(GLParam *p) {
|
||||
clear_depth = p[1].f;
|
||||
}
|
||||
|
||||
void GLContext::glopClearStencil(GLParam *p) {
|
||||
clear_stencil = p[1].i & 0xFF;
|
||||
}
|
||||
|
||||
void GLContext::glopClear(GLParam *p) {
|
||||
int mask = p[1].i;
|
||||
int z = (int)(clear_depth * ((1 << ZB_Z_BITS) - 1));
|
||||
int r = (int)(clear_color.X * 255);
|
||||
int g = (int)(clear_color.Y * 255);
|
||||
int b = (int)(clear_color.Z * 255);
|
||||
int s = (int)(clear_stencil);
|
||||
|
||||
issueDrawCall(new ClearBufferDrawCall(mask & TGL_DEPTH_BUFFER_BIT, z,
|
||||
mask & TGL_COLOR_BUFFER_BIT, r, g, b,
|
||||
mask & TGL_STENCIL_BUFFER_BIT, s));
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
469
graphics/tinygl/clip.cpp
Normal file
469
graphics/tinygl/clip.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
#define CLIP_XMIN (1 << 0)
|
||||
#define CLIP_XMAX (1 << 1)
|
||||
#define CLIP_YMIN (1 << 2)
|
||||
#define CLIP_YMAX (1 << 3)
|
||||
#define CLIP_ZMIN (1 << 4)
|
||||
#define CLIP_ZMAX (1 << 5)
|
||||
|
||||
void GLContext::gl_transform_to_viewport(GLVertex *v) {
|
||||
float winv, result;
|
||||
|
||||
// coordinates
|
||||
winv = (float)(1.0 / v->pc.W);
|
||||
// Compute and clamp X coordinate
|
||||
result = v->pc.X * winv * viewport.scale.X + viewport.trans.X;
|
||||
if (result > (float)INT_MAX)
|
||||
v->zp.x = INT_MAX;
|
||||
else if (result < (float)INT_MIN)
|
||||
v->zp.x = INT_MIN;
|
||||
else
|
||||
v->zp.x = (int)result;
|
||||
|
||||
// Compute and clamp Y coordinate
|
||||
result = v->pc.Y * winv * viewport.scale.Y + viewport.trans.Y;
|
||||
if (result > (float)INT_MAX)
|
||||
v->zp.y = INT_MAX;
|
||||
else if (result < (float)INT_MIN)
|
||||
v->zp.y = INT_MIN;
|
||||
else
|
||||
v->zp.y = (int)result;
|
||||
|
||||
// Compute and clamp Z coordinate
|
||||
result = v->pc.Z * winv * viewport.scale.Z + viewport.trans.Z;
|
||||
if (result > (float)INT_MAX)
|
||||
v->zp.z = INT_MAX;
|
||||
else if (result < (float)INT_MIN)
|
||||
v->zp.z = INT_MIN;
|
||||
else
|
||||
v->zp.z = (int)result;
|
||||
|
||||
|
||||
// color
|
||||
v->zp.r = (int)(v->color.X * ZB_POINT_RED_MAX);
|
||||
v->zp.g = (int)(v->color.Y * ZB_POINT_GREEN_MAX);
|
||||
v->zp.b = (int)(v->color.Z * ZB_POINT_BLUE_MAX);
|
||||
v->zp.a = (int)(v->color.W * ZB_POINT_ALPHA_MAX);
|
||||
|
||||
// texture
|
||||
if (texture_2d_enabled) {
|
||||
v->zp.s = (int)(v->tex_coord.X * ZB_POINT_ST_MAX);
|
||||
v->zp.t = (int)(v->tex_coord.Y * ZB_POINT_ST_MAX);
|
||||
}
|
||||
|
||||
// fog
|
||||
if (fog_enabled) {
|
||||
v->zp.f = (int)(v->fog_factor * ZB_FOG_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_add_select1(int z1, int z2, int z3) {
|
||||
int min, max;
|
||||
|
||||
min = max = z1;
|
||||
if (z2 < min)
|
||||
min = z2;
|
||||
if (z3 < min)
|
||||
min = z3;
|
||||
if (z2 > max)
|
||||
max = z2;
|
||||
if (z3 > max)
|
||||
max = z3;
|
||||
|
||||
gl_add_select(0xffffffff - min, 0xffffffff - max);
|
||||
}
|
||||
|
||||
// point
|
||||
|
||||
void GLContext::gl_draw_point(GLVertex *p0) {
|
||||
if (p0->clip_code == 0) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
gl_add_select(p0->zp.z, p0->zp.z);
|
||||
} else {
|
||||
fb->plot(&p0->zp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// line
|
||||
|
||||
static inline void interpolate_color(GLContext *c, GLVertex *q, GLVertex *p0, GLVertex *p1, float t) {
|
||||
if (c->current_shade_model == TGL_SMOOTH)
|
||||
q->color = p0->color + (p1->color - p0->color) * t;
|
||||
else
|
||||
q->color = p0->color;
|
||||
}
|
||||
|
||||
static inline void interpolate(GLContext *c, GLVertex *q, GLVertex *p0, GLVertex *p1, float t) {
|
||||
q->pc = p0->pc + (p1->pc - p0->pc) * t;
|
||||
interpolate_color(c, q, p0, p1, t);
|
||||
}
|
||||
|
||||
// Line Clipping
|
||||
|
||||
// Line Clipping algorithm from 'Computer Graphics', Principles and
|
||||
// Practice
|
||||
static inline int ClipLine1(float denom, float num, float *tmin, float *tmax) {
|
||||
float t;
|
||||
|
||||
if (denom > 0) {
|
||||
t = num / denom;
|
||||
if (t > *tmax)
|
||||
return 0;
|
||||
if (t > *tmin)
|
||||
*tmin = t;
|
||||
} else if (denom < 0) {
|
||||
t = num / denom;
|
||||
if (t < *tmin)
|
||||
return 0;
|
||||
if (t < *tmax)
|
||||
*tmax = t;
|
||||
} else if (num > 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GLContext::gl_draw_line(GLVertex *p1, GLVertex *p2) {
|
||||
float dx, dy, dz, dw, x1, y1, z1, w1;
|
||||
float tmin, tmax;
|
||||
GLVertex q1, q2;
|
||||
int cc1, cc2;
|
||||
|
||||
cc1 = p1->clip_code;
|
||||
cc2 = p2->clip_code;
|
||||
|
||||
if ((cc1 | cc2) == 0) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
gl_add_select1(p1->zp.z, p2->zp.z, p2->zp.z);
|
||||
} else {
|
||||
if (depth_test_enabled)
|
||||
fb->fillLineZ(&p1->zp, &p2->zp);
|
||||
else
|
||||
fb->fillLine(&p1->zp, &p2->zp);
|
||||
}
|
||||
} else if ((cc1 & cc2) != 0) {
|
||||
return;
|
||||
} else {
|
||||
dx = p2->pc.X - p1->pc.X;
|
||||
dy = p2->pc.Y - p1->pc.Y;
|
||||
dz = p2->pc.Z - p1->pc.Z;
|
||||
dw = p2->pc.W - p1->pc.W;
|
||||
x1 = p1->pc.X;
|
||||
y1 = p1->pc.Y;
|
||||
z1 = p1->pc.Z;
|
||||
w1 = p1->pc.W;
|
||||
|
||||
tmin = 0;
|
||||
tmax = 1;
|
||||
if (ClipLine1(dx + dw, -x1 - w1, &tmin, &tmax) &&
|
||||
ClipLine1(-dx + dw, x1 - w1, &tmin, &tmax) &&
|
||||
ClipLine1(dy + dw, -y1 - w1, &tmin, &tmax) &&
|
||||
ClipLine1(-dy + dw, y1 - w1, &tmin, &tmax) &&
|
||||
ClipLine1(dz + dw, -z1 - w1, &tmin, &tmax) &&
|
||||
ClipLine1(-dz + dw, z1 - w1, &tmin, &tmax)) {
|
||||
interpolate(this, &q1, p1, p2, tmin);
|
||||
interpolate(this, &q2, p1, p2, tmax);
|
||||
gl_transform_to_viewport(&q1);
|
||||
gl_transform_to_viewport(&q2);
|
||||
|
||||
if (depth_test_enabled)
|
||||
fb->fillLineZ(&q1.zp, &q2.zp);
|
||||
else
|
||||
fb->fillLine(&q1.zp, &q2.zp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// triangle
|
||||
|
||||
// Clipping
|
||||
|
||||
// We clip the segment [a,b] against the 6 planes of the normal volume.
|
||||
// We compute the point 'c' of intersection and the value of the parameter 't'
|
||||
// of the intersection if x=a+t(b-a).
|
||||
|
||||
#define clip_func(name, sign, dir, dir1, dir2) \
|
||||
static float name(Vector4 *c, Vector4 *a, Vector4 *b) { \
|
||||
float t, dX, dY, dZ, dW, den;\
|
||||
dX = (b->X - a->X); \
|
||||
dY = (b->Y - a->Y); \
|
||||
dZ = (b->Z - a->Z); \
|
||||
dW = (b->W - a->W); \
|
||||
den = -(sign d ## dir) + dW; \
|
||||
if (den == 0) \
|
||||
t = 0; \
|
||||
else \
|
||||
t = (sign a->dir - a->W) / den; \
|
||||
c-> dir1 = (a->dir1 + t * d ## dir1); \
|
||||
c-> dir2 = (a->dir2 + t * d ## dir2); \
|
||||
c->W = (a->W + t * dW); \
|
||||
c-> dir = (sign c->W); \
|
||||
return t; \
|
||||
}
|
||||
|
||||
clip_func(clip_xmin, -, X, Y, Z)
|
||||
clip_func(clip_xmax, +, X, Y, Z)
|
||||
clip_func(clip_ymin, -, Y, X, Z)
|
||||
clip_func(clip_ymax, +, Y, X, Z)
|
||||
clip_func(clip_zmin, -, Z, X, Y)
|
||||
clip_func(clip_zmax, +, Z, X, Y)
|
||||
|
||||
float(*const clip_proc[6])(Vector4 *, Vector4 *, Vector4 *) = {
|
||||
clip_xmin, clip_xmax,
|
||||
clip_ymin, clip_ymax,
|
||||
clip_zmin, clip_zmax
|
||||
};
|
||||
|
||||
static inline void updateTmp(GLContext *c, GLVertex *q, GLVertex *p0, GLVertex *p1, float t) {
|
||||
interpolate_color(c, q, p0, p1, t);
|
||||
|
||||
if (c->texture_2d_enabled) {
|
||||
// NOTE: This could be implemented with operator overloading,
|
||||
// but i'm not 100% sure that we can completely disregard Z and W components so I'm leaving it like this for now.
|
||||
q->tex_coord.X = (p0->tex_coord.X + (p1->tex_coord.X - p0->tex_coord.X) * t);
|
||||
q->tex_coord.Y = (p0->tex_coord.Y + (p1->tex_coord.Y - p0->tex_coord.Y) * t);
|
||||
}
|
||||
|
||||
q->clip_code = gl_clipcode(q->pc.X, q->pc.Y, q->pc.Z, q->pc.W);
|
||||
if (q->clip_code == 0)
|
||||
c->gl_transform_to_viewport(q);
|
||||
}
|
||||
|
||||
void GLContext::gl_draw_triangle(GLVertex *p0, GLVertex *p1, GLVertex *p2) {
|
||||
int co, c_and, cc[3], front;
|
||||
float norm;
|
||||
|
||||
cc[0] = p0->clip_code;
|
||||
cc[1] = p1->clip_code;
|
||||
cc[2] = p2->clip_code;
|
||||
|
||||
co = cc[0] | cc[1] | cc[2];
|
||||
|
||||
// we handle the non clipped case here to go faster
|
||||
if (co == 0) {
|
||||
norm = (float)(p1->zp.x - p0->zp.x) * (float)(p2->zp.y - p0->zp.y) -
|
||||
(float)(p2->zp.x - p0->zp.x) * (float)(p1->zp.y - p0->zp.y);
|
||||
if (norm == 0)
|
||||
return;
|
||||
|
||||
front = norm < 0.0;
|
||||
front = front ^ current_front_face;
|
||||
|
||||
// back face culling
|
||||
if (cull_face_enabled) {
|
||||
// most used case first */
|
||||
if (current_cull_face == TGL_BACK) {
|
||||
if (front == 0)
|
||||
return;
|
||||
draw_triangle_front(this, p0, p1, p2);
|
||||
} else if (current_cull_face == TGL_FRONT) {
|
||||
if (front != 0)
|
||||
return;
|
||||
draw_triangle_back(this, p0, p1, p2);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// no culling
|
||||
if (front) {
|
||||
draw_triangle_front(this, p0, p1, p2);
|
||||
} else {
|
||||
draw_triangle_back(this, p0, p1, p2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c_and = cc[0] & cc[1] & cc[2];
|
||||
if (c_and == 0) {
|
||||
gl_draw_triangle_clip(p0, p1, p2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_draw_triangle_clip(GLVertex *p0, GLVertex *p1, GLVertex *p2, int clip_bit) {
|
||||
int co, c_and, co1, cc[3], edge_flag_tmp, clip_mask;
|
||||
GLVertex tmp1, tmp2, *q[3];
|
||||
float tt;
|
||||
|
||||
cc[0] = p0->clip_code;
|
||||
cc[1] = p1->clip_code;
|
||||
cc[2] = p2->clip_code;
|
||||
|
||||
co = cc[0] | cc[1] | cc[2];
|
||||
if (co == 0) {
|
||||
gl_draw_triangle(p0, p1, p2);
|
||||
} else {
|
||||
c_and = cc[0] & cc[1] & cc[2];
|
||||
// the triangle is completely outside
|
||||
if (c_and != 0)
|
||||
return;
|
||||
|
||||
// find the next direction to clip
|
||||
while (clip_bit < 6 && (co & (1 << clip_bit)) == 0) {
|
||||
clip_bit++;
|
||||
}
|
||||
|
||||
// this test can be true only in case of rounding errors
|
||||
if (clip_bit == 6) {
|
||||
#if 0
|
||||
printf("Error:\n");
|
||||
printf("%f %f %f %f\n", p0->pc.X, p0->pc.Y, p0->pc.Z, p0->pc.W);
|
||||
printf("%f %f %f %f\n", p1->pc.X, p1->pc.Y, p1->pc.Z, p1->pc.W);
|
||||
printf("%f %f %f %f\n", p2->pc.X, p2->pc.Y, p2->pc.Z, p2->pc.W);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
clip_mask = 1 << clip_bit;
|
||||
co1 = (cc[0] ^ cc[1] ^ cc[2]) & clip_mask;
|
||||
|
||||
if (co1) {
|
||||
// one point outside
|
||||
if (cc[0] & clip_mask) {
|
||||
q[0] = p0; q[1] = p1; q[2] = p2;
|
||||
} else if (cc[1] & clip_mask) {
|
||||
q[0] = p1; q[1] = p2; q[2] = p0;
|
||||
} else {
|
||||
q[0] = p2; q[1] = p0; q[2] = p1;
|
||||
}
|
||||
|
||||
tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
|
||||
updateTmp(this, &tmp1, q[0], q[1], tt);
|
||||
|
||||
tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
|
||||
updateTmp(this, &tmp2, q[0], q[2], tt);
|
||||
|
||||
tmp1.edge_flag = q[0]->edge_flag;
|
||||
edge_flag_tmp = q[2]->edge_flag;
|
||||
q[2]->edge_flag = 0;
|
||||
gl_draw_triangle_clip(&tmp1, q[1], q[2], clip_bit + 1);
|
||||
|
||||
tmp2.edge_flag = 1;
|
||||
tmp1.edge_flag = 0;
|
||||
q[2]->edge_flag = edge_flag_tmp;
|
||||
gl_draw_triangle_clip(&tmp2, &tmp1, q[2], clip_bit + 1);
|
||||
} else {
|
||||
// two points outside
|
||||
if ((cc[0] & clip_mask) == 0) {
|
||||
q[0] = p0; q[1] = p1; q[2] = p2;
|
||||
} else if ((cc[1] & clip_mask) == 0) {
|
||||
q[0] = p1; q[1] = p2; q[2] = p0;
|
||||
} else {
|
||||
q[0] = p2; q[1] = p0; q[2] = p1;
|
||||
}
|
||||
|
||||
tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
|
||||
updateTmp(this, &tmp1, q[0], q[1], tt);
|
||||
|
||||
tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
|
||||
updateTmp(this, &tmp2, q[0], q[2], tt);
|
||||
|
||||
tmp1.edge_flag = 1;
|
||||
tmp2.edge_flag = q[2]->edge_flag;
|
||||
gl_draw_triangle_clip(q[0], &tmp1, &tmp2, clip_bit + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_draw_triangle_select(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
|
||||
c->gl_add_select1(p0->zp.z, p1->zp.z, p2->zp.z);
|
||||
}
|
||||
|
||||
int count_triangles, count_triangles_textured, count_pixels;
|
||||
|
||||
void GLContext::gl_draw_triangle_fill(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
|
||||
if (c->_profilingEnabled) {
|
||||
int norm;
|
||||
assert(p0->zp.x >= 0 && p0->zp.x < c->fb->getPixelBufferWidth());
|
||||
assert(p0->zp.y >= 0 && p0->zp.y < c->fb->getPixelBufferHeight());
|
||||
assert(p1->zp.x >= 0 && p1->zp.x < c->fb->getPixelBufferWidth());
|
||||
assert(p1->zp.y >= 0 && p1->zp.y < c->fb->getPixelBufferHeight());
|
||||
assert(p2->zp.x >= 0 && p2->zp.x < c->fb->getPixelBufferWidth());
|
||||
assert(p2->zp.y >= 0 && p2->zp.y < c->fb->getPixelBufferHeight());
|
||||
|
||||
norm = (p1->zp.x - p0->zp.x) * (p2->zp.y - p0->zp.y) -
|
||||
(p2->zp.x - p0->zp.x) * (p1->zp.y - p0->zp.y);
|
||||
count_pixels += abs(norm) / 2;
|
||||
count_triangles++;
|
||||
}
|
||||
|
||||
if (!c->color_mask_red && !c->color_mask_green && !c->color_mask_blue && !c->color_mask_alpha) {
|
||||
c->fb->fillTriangleDepthOnly(&p0->zp, &p1->zp, &p2->zp);
|
||||
} else if (c->texture_2d_enabled && c->current_texture->images[0].pixmap) {
|
||||
if (c->_profilingEnabled) {
|
||||
count_triangles_textured++;
|
||||
}
|
||||
c->fb->setTexture(c->current_texture->images[0].pixmap, c->texture_wrap_s, c->texture_wrap_t);
|
||||
if (c->current_shade_model == TGL_SMOOTH) {
|
||||
c->fb->fillTriangleTextureMappingPerspectiveSmooth(&p0->zp, &p1->zp, &p2->zp);
|
||||
} else {
|
||||
c->fb->fillTriangleTextureMappingPerspectiveFlat(&p0->zp, &p1->zp, &p2->zp);
|
||||
}
|
||||
} else if (c->current_shade_model == TGL_SMOOTH) {
|
||||
c->fb->fillTriangleSmooth(&p0->zp, &p1->zp, &p2->zp);
|
||||
} else {
|
||||
c->fb->fillTriangleFlat(&p0->zp, &p1->zp, &p2->zp);
|
||||
}
|
||||
}
|
||||
|
||||
// Render a clipped triangle in line mode
|
||||
|
||||
void GLContext::gl_draw_triangle_line(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
|
||||
if (c->depth_test_enabled) {
|
||||
if (p0->edge_flag)
|
||||
c->fb->fillLineZ(&p0->zp, &p1->zp);
|
||||
if (p1->edge_flag)
|
||||
c->fb->fillLineZ(&p1->zp, &p2->zp);
|
||||
if (p2->edge_flag)
|
||||
c->fb->fillLineZ(&p2->zp, &p0->zp);
|
||||
} else {
|
||||
if (p0->edge_flag)
|
||||
c->fb->fillLine(&p0->zp, &p1->zp);
|
||||
if (p1->edge_flag)
|
||||
c->fb->fillLine(&p1->zp, &p2->zp);
|
||||
if (p2->edge_flag)
|
||||
c->fb->fillLine(&p2->zp, &p0->zp);
|
||||
}
|
||||
}
|
||||
|
||||
// Render a clipped triangle in point mode
|
||||
void GLContext::gl_draw_triangle_point(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
|
||||
if (p0->edge_flag)
|
||||
c->fb->plot(&p0->zp);
|
||||
if (p1->edge_flag)
|
||||
c->fb->plot(&p1->zp);
|
||||
if (p2->edge_flag)
|
||||
c->fb->plot(&p2->zp);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
146
graphics/tinygl/colormasks.h
Normal file
146
graphics/tinygl/colormasks.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_COLORMASKS_H
|
||||
#define GRAPHICS_TINYGL_COLORMASKS_H
|
||||
|
||||
#include "graphics/tinygl/gl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
template<uint Format, uint Type>
|
||||
struct ColorMasks {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ColorMasks<TGL_RGB, TGL_UNSIGNED_SHORT_5_6_5> {
|
||||
enum : uint {
|
||||
kBytesPerPixel = 2,
|
||||
|
||||
kAlphaBits = 0,
|
||||
kRedBits = 5,
|
||||
kGreenBits = 6,
|
||||
kBlueBits = 5,
|
||||
|
||||
kAlphaShift = 0,
|
||||
kRedShift = kGreenBits+kBlueBits,
|
||||
kGreenShift = kBlueBits,
|
||||
kBlueShift = 0,
|
||||
|
||||
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
|
||||
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
|
||||
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
|
||||
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
|
||||
|
||||
kRedBlueMask = kRedMask | kBlueMask,
|
||||
};
|
||||
|
||||
typedef uint16 PixelType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ColorMasks<TGL_RGBA, TGL_UNSIGNED_SHORT_5_5_5_1> {
|
||||
enum {
|
||||
kBytesPerPixel = 2,
|
||||
|
||||
kAlphaBits = 1,
|
||||
kRedBits = 5,
|
||||
kGreenBits = 5,
|
||||
kBlueBits = 5,
|
||||
|
||||
kAlphaShift = 0,
|
||||
kRedShift = kGreenBits+kBlueBits+kAlphaBits,
|
||||
kGreenShift = kBlueBits+kAlphaBits,
|
||||
kBlueShift = kAlphaBits,
|
||||
|
||||
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
|
||||
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
|
||||
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
|
||||
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
|
||||
|
||||
kRedBlueMask = kRedMask | kBlueMask
|
||||
};
|
||||
|
||||
typedef uint16 PixelType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ColorMasks<TGL_RGBA, TGL_UNSIGNED_SHORT_4_4_4_4> {
|
||||
enum {
|
||||
kBytesPerPixel = 2,
|
||||
|
||||
kAlphaBits = 4,
|
||||
kRedBits = 4,
|
||||
kGreenBits = 4,
|
||||
kBlueBits = 4,
|
||||
|
||||
kAlphaShift = 0,
|
||||
kRedShift = kGreenBits+kBlueBits+kAlphaBits,
|
||||
kGreenShift = kBlueBits+kAlphaBits,
|
||||
kBlueShift = kAlphaBits,
|
||||
|
||||
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
|
||||
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
|
||||
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
|
||||
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
|
||||
|
||||
kRedBlueMask = kRedMask | kBlueMask
|
||||
};
|
||||
|
||||
typedef uint16 PixelType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ColorMasks<TGL_RGBA, TGL_UNSIGNED_BYTE> {
|
||||
enum {
|
||||
kBytesPerPixel = 4,
|
||||
|
||||
kAlphaBits = 8,
|
||||
kRedBits = 8,
|
||||
kGreenBits = 8,
|
||||
kBlueBits = 8,
|
||||
|
||||
#if defined(SCUMM_LITTLE_ENDIAN)
|
||||
kAlphaShift = kRedBits+kGreenBits+kBlueBits,
|
||||
kRedShift = 0,
|
||||
kGreenShift = kRedBits,
|
||||
kBlueShift = kRedBits+kGreenBits,
|
||||
#else
|
||||
kAlphaShift = 0,
|
||||
kRedShift = kGreenBits+kBlueBits+kAlphaBits,
|
||||
kGreenShift = kBlueBits+kAlphaBits,
|
||||
kBlueShift = kAlphaBits,
|
||||
#endif
|
||||
|
||||
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
|
||||
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
|
||||
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
|
||||
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
|
||||
|
||||
kRedBlueMask = kRedMask | kBlueMask,
|
||||
};
|
||||
|
||||
typedef uint32 PixelType;
|
||||
};
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
#endif
|
||||
92
graphics/tinygl/fog.cpp
Normal file
92
graphics/tinygl/fog.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopFog(GLParam *p) {
|
||||
int pname = p[1].i;
|
||||
|
||||
switch (pname) {
|
||||
case TGL_FOG_MODE:
|
||||
switch (p[2].i) {
|
||||
case TGL_LINEAR:
|
||||
case TGL_EXP:
|
||||
case TGL_EXP2:
|
||||
fog_mode = p[2].i;
|
||||
break;
|
||||
default:
|
||||
error("tglFog: unknown fog mode");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TGL_FOG_DENSITY:
|
||||
if (p[2].f < 0.0f) {
|
||||
error("tglFog: fog density negate param");
|
||||
return;
|
||||
}
|
||||
fog_density = p[2].f;
|
||||
break;
|
||||
case TGL_FOG_START:
|
||||
fog_start = p[2].f;
|
||||
break;
|
||||
case TGL_FOG_END:
|
||||
fog_end = p[2].f;
|
||||
break;
|
||||
case TGL_FOG_COLOR:
|
||||
fog_color = Vector4(clampf(p[2].f, 0.0f, 1.0f),
|
||||
clampf(p[3].f, 0.0f, 1.0f),
|
||||
clampf(p[4].f, 0.0f, 1.0f),
|
||||
clampf(p[5].f, 0.0f, 1.0f));
|
||||
break;
|
||||
default:
|
||||
error("tglFog: param not implemented");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_calc_fog_factor(GLVertex *v) {
|
||||
float eye_distance = sqrtf(v->ec.X * v->ec.X + v->ec.Y * v->ec.Y + v->ec.Z * v->ec.Z);
|
||||
|
||||
switch (fog_mode) {
|
||||
case TGL_LINEAR: {
|
||||
float fog_distance = 1.0f;
|
||||
if (fog_start != fog_end)
|
||||
fog_distance /= (fog_end - fog_start);
|
||||
v->fog_factor = (fog_end - eye_distance) * fog_distance;
|
||||
}
|
||||
break;
|
||||
case TGL_EXP:
|
||||
v->fog_factor = expf(-fog_density * eye_distance);
|
||||
break;
|
||||
case TGL_EXP2:
|
||||
v->fog_factor = expf(-(fog_density * fog_density * eye_distance * eye_distance));
|
||||
break;
|
||||
default:
|
||||
v->fog_factor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
v->fog_factor = clampf(v->fog_factor, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
982
graphics/tinygl/get.cpp
Normal file
982
graphics/tinygl/get.cpp
Normal file
@@ -0,0 +1,982 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
#define MAX_INTEGER 2147483647
|
||||
#define FLOAT_TO_INTEGER(f) ((TGLint)(f * MAX_INTEGER))
|
||||
#define VALUE_TO_BOOLEAN(f) ((f) ? TGL_TRUE : TGL_FALSE)
|
||||
|
||||
void GLContext::gl_get_pname(TGLenum pname, union uglValue *data, eDataType &dataType) {
|
||||
int mnr = 0;
|
||||
|
||||
switch (pname) {
|
||||
case TGL_ACCUM_ALPHA_BITS:
|
||||
// fall through
|
||||
case TGL_ACCUM_BLUE_BITS:
|
||||
// fall through
|
||||
case TGL_ACCUM_CLEAR_VALUE:
|
||||
// fall through
|
||||
case TGL_ACCUM_GREEN_BITS:
|
||||
// fall through
|
||||
case TGL_ACCUM_RED_BITS:
|
||||
data->_int = 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_ALIASED_LINE_WIDTH_RANGE:
|
||||
error("gl_get_pname: TGL_ALIASED_LINE_WIDTH_RANGE option not implemented");
|
||||
break;
|
||||
case TGL_ALIASED_POINT_SIZE_RANGE:
|
||||
error("gl_get_pname: TGL_ALIASED_POINT_SIZE_RANGE option not implemented");
|
||||
break;
|
||||
case TGL_ALPHA_BIAS:
|
||||
// fall through
|
||||
case TGL_RED_BIAS:
|
||||
// fall through
|
||||
case TGL_GREEN_BIAS:
|
||||
// fall through
|
||||
case TGL_BLUE_BIAS:
|
||||
// fall through
|
||||
case TGL_DEPTH_BIAS:
|
||||
data->_float = 0.0f;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_ALPHA_SCALE:
|
||||
// fall through
|
||||
case TGL_RED_SCALE:
|
||||
// fall through
|
||||
case TGL_GREEN_SCALE:
|
||||
// fall through
|
||||
case TGL_DEPTH_SCALE:
|
||||
// fall through
|
||||
case TGL_BLUE_SCALE:
|
||||
data->_float = 1.0f;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_ALPHA_BITS:
|
||||
data->_int = fb->getPixelFormat().aBits();
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_RED_BITS:
|
||||
data->_int = fb->getPixelFormat().rBits();
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_GREEN_BITS:
|
||||
data->_int = fb->getPixelFormat().gBits();
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_BLUE_BITS:
|
||||
data->_int = fb->getPixelFormat().bBits();
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_ALPHA_TEST:
|
||||
data->_int = (TGLint)alpha_test_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_ALPHA_TEST_FUNC:
|
||||
data->_int = alpha_test_func;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_ALPHA_TEST_REF:
|
||||
data->_float = alpha_test_ref_val / 255.0f;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_ATTRIB_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_ALIASED_POINT_SIZE_RANGE option not implemented");
|
||||
break;
|
||||
case TGL_AUTO_NORMAL:
|
||||
data->_int = 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_AUX_BUFFERS:
|
||||
error("gl_get_pname: TGL_AUX_BUFFERS option not implemented");
|
||||
break;
|
||||
case TGL_BLEND:
|
||||
data->_int = (TGLint)blending_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_BLEND_DST:
|
||||
data->_int = destination_blending_factor;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_BLEND_SRC:
|
||||
data->_int = source_blending_factor;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_CLIENT_ATTRIB_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_CLIENT_ATTRIB_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_CLIP_PLANE0:
|
||||
// fall through
|
||||
case TGL_CLIP_PLANE1:
|
||||
// fall through
|
||||
case TGL_CLIP_PLANE2:
|
||||
// fall through
|
||||
case TGL_CLIP_PLANE3:
|
||||
// fall through
|
||||
case TGL_CLIP_PLANE4:
|
||||
// fall through
|
||||
case TGL_CLIP_PLANE5:
|
||||
error("gl_get_pname: TGL_CLIP_PLANEx option not implemented");
|
||||
break;
|
||||
case TGL_COLOR_ARRAY:
|
||||
data->_int = (TGLint)(color_array != nullptr);
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_ARRAY_SIZE:
|
||||
data->_int = color_array_size;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_ARRAY_STRIDE:
|
||||
data->_int = color_array_stride;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_ARRAY_TYPE:
|
||||
data->_int = color_array_type;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_CLEAR_VALUE:
|
||||
data->_float4[0] = clear_color._v[0];
|
||||
data->_float4[1] = clear_color._v[1];
|
||||
data->_float4[2] = clear_color._v[2];
|
||||
data->_float4[3] = clear_color._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_COLOR_LOGIC_OP:
|
||||
error("gl_get_pname: TGL_COLOR_LOGIC_OP option not implemented");
|
||||
break;
|
||||
case TGL_COLOR_MATERIAL:
|
||||
data->_int = (TGLint)color_material_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_MATERIAL_FACE:
|
||||
data->_int = current_color_material_mode;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_MATERIAL_PARAMETER:
|
||||
data->_int = current_color_material_type;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_COLOR_WRITEMASK:
|
||||
data->_int4[0] = (TGLint)TGL_TRUE;
|
||||
data->_int4[1] = (TGLint)TGL_TRUE;
|
||||
data->_int4[2] = (TGLint)TGL_TRUE;
|
||||
data->_int4[3] = (TGLint)TGL_TRUE;
|
||||
dataType = kInt4Type;
|
||||
break;
|
||||
case TGL_CULL_FACE:
|
||||
data->_int = (TGLint)cull_face_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_CULL_FACE_MODE:
|
||||
data->_int = (TGLint)current_cull_face;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_CURRENT_COLOR:
|
||||
data->_float4[0] = current_color._v[0];
|
||||
data->_float4[1] = current_color._v[1];
|
||||
data->_float4[2] = current_color._v[2];
|
||||
data->_float4[3] = current_color._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_CURRENT_INDEX:
|
||||
error("gl_get_pname: TGL_CURRENT_INDEX not supported");
|
||||
break;
|
||||
case TGL_CURRENT_NORMAL:
|
||||
data->_float4[0] = current_normal._v[0];
|
||||
data->_float4[1] = current_normal._v[1];
|
||||
data->_float4[2] = current_normal._v[2];
|
||||
data->_float4[3] = current_normal._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_CURRENT_RASTER_INDEX:
|
||||
error("gl_get_pname: TGL_CURRENT_RASTER_INDEX not supported");
|
||||
break;
|
||||
case TGL_CURRENT_RASTER_COLOR:
|
||||
// fall through
|
||||
case TGL_CURRENT_RASTER_DISTANCE:
|
||||
// fall through
|
||||
case TGL_CURRENT_RASTER_POSITION:
|
||||
// fall through
|
||||
case TGL_CURRENT_RASTER_POSITION_VALID:
|
||||
// fall through
|
||||
case TGL_CURRENT_RASTER_TEXTURE_COORDS:
|
||||
error("gl_get_pname: TGL_CURRENT_RASTER_x options not implemented");
|
||||
break;
|
||||
case TGL_CURRENT_TEXTURE_COORDS:
|
||||
data->_float4[0] = current_tex_coord._v[0];
|
||||
data->_float4[1] = current_tex_coord._v[1];
|
||||
data->_float4[2] = current_tex_coord._v[2];
|
||||
data->_float4[3] = current_tex_coord._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_DEPTH_BITS:
|
||||
data->_int = 16;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DEPTH_CLEAR_VALUE:
|
||||
data->_float = clear_depth;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_DEPTH_FUNC:
|
||||
data->_int = depth_func;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DEPTH_RANGE:
|
||||
data->_float2[0] = 1.0f;
|
||||
data->_float2[1] = -1.0f;
|
||||
dataType = kFloat2Type;
|
||||
break;
|
||||
case TGL_DEPTH_TEST:
|
||||
data->_int = (TGLint)depth_test_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DEPTH_WRITEMASK:
|
||||
data->_int = (TGLint)depth_write_mask;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DITHER:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DOUBLEBUFFER:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_DRAW_BUFFER:
|
||||
error("gl_get_pname: TGL_DRAW_BUFFER option not implemented");
|
||||
break;
|
||||
case TGL_EDGE_FLAG:
|
||||
data->_int = current_edge_flag;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_EDGE_FLAG_ARRAY:
|
||||
error("gl_get_pname: TGL_EDGE_FLAG_ARRAY option not implemented");
|
||||
break;
|
||||
case TGL_EDGE_FLAG_ARRAY_STRIDE:
|
||||
error("gl_get_pname: TGL_EDGE_FLAG_ARRAY_STRIDE option not implemented");
|
||||
break;
|
||||
case TGL_FEEDBACK_BUFFER_SIZE:
|
||||
// fall through
|
||||
case TGL_FEEDBACK_BUFFER_TYPE:
|
||||
error("gl_get_pname: TGL_FEEDBACK_BUFFER_x option not implemented");
|
||||
break;
|
||||
case TGL_FOG:
|
||||
data->_int = (TGLint)fog_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_FOG_COLOR:
|
||||
data->_float4[0] = fog_color._v[0];
|
||||
data->_float4[1] = fog_color._v[1];
|
||||
data->_float4[2] = fog_color._v[2];
|
||||
data->_float4[3] = fog_color._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_FOG_DENSITY:
|
||||
data->_float = fog_density;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_FOG_END:
|
||||
data->_float = fog_end;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_FOG_HINT:
|
||||
data->_int = TGL_DONT_CARE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_FOG_INDEX:
|
||||
error("gl_get_pname: TGL_FOG_INDEX not supported");
|
||||
break;
|
||||
case TGL_FOG_MODE:
|
||||
data->_int = fog_mode;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_FOG_START:
|
||||
data->_float = fog_start;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_FRONT_FACE:
|
||||
data->_int = (current_front_face == 0) ? TGL_CCW : TGL_CW;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_INDEX_ARRAY:
|
||||
// fall through
|
||||
case TGL_INDEX_ARRAY_STRIDE:
|
||||
// fall through
|
||||
case TGL_INDEX_ARRAY_TYPE:
|
||||
// fall through
|
||||
case TGL_INDEX_BITS:
|
||||
// fall through
|
||||
case TGL_INDEX_CLEAR_VALUE:
|
||||
// fall through
|
||||
case TGL_INDEX_LOGIC_OP:
|
||||
// fall through
|
||||
case TGL_INDEX_MODE:
|
||||
// fall through
|
||||
case TGL_INDEX_OFFSET:
|
||||
// fall through
|
||||
case TGL_INDEX_SHIFT:
|
||||
// fall through
|
||||
case TGL_INDEX_WRITEMASK:
|
||||
error("gl_get_pname: TGL_INDEX_x not supported");
|
||||
break;
|
||||
case TGL_LIGHT0:
|
||||
data->_int = (TGLint)lights[0].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT1:
|
||||
data->_int = (TGLint)lights[1].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT2:
|
||||
data->_int = (TGLint)lights[2].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT3:
|
||||
data->_int = (TGLint)lights[3].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT4:
|
||||
data->_int = (TGLint)lights[4].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT5:
|
||||
data->_int = (TGLint)lights[5].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT6:
|
||||
data->_int = (TGLint)lights[6].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT7:
|
||||
data->_int = (TGLint)lights[7].enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHTING:
|
||||
data->_int = (TGLint)lighting_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_AMBIENT:
|
||||
data->_float4[0] = ambient_light_model._v[0];
|
||||
data->_float4[1] = ambient_light_model._v[1];
|
||||
data->_float4[2] = ambient_light_model._v[2];
|
||||
data->_float4[3] = ambient_light_model._v[3];
|
||||
dataType = kFloat4Type;
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_COLOR_CONTROL:
|
||||
error("gl_get_pname: TGL_LIGHT_MODEL_COLOR_CONTROL option not implemented");
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_LOCAL_VIEWER:
|
||||
data->_int = local_light_model;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_TWO_SIDE:
|
||||
data->_int = light_model_two_side;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LINE_SMOOTH:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LINE_SMOOTH_HINT:
|
||||
data->_int = TGL_DONT_CARE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_LINE_STIPPLE:
|
||||
// fall through
|
||||
case TGL_LINE_STIPPLE_PATTERN:
|
||||
// fall through
|
||||
case TGL_LINE_STIPPLE_REPEAT:
|
||||
// fall through
|
||||
error("gl_get_pname: TGL_LINE_STIPPLE_x option not implemented");
|
||||
break;
|
||||
case TGL_LINE_WIDTH:
|
||||
// fall through
|
||||
case TGL_LINE_WIDTH_GRANULARITY:
|
||||
// fall through
|
||||
case TGL_LINE_WIDTH_RANGE:
|
||||
error("gl_get_pname: TGL_LINE_x option not implemented");
|
||||
break;
|
||||
case TGL_LIST_BASE:
|
||||
// fall through
|
||||
case TGL_LIST_INDEX:
|
||||
// fall through
|
||||
case TGL_LIST_MODE:
|
||||
error("gl_get_pname: TGL_LIST_x option not implemented");
|
||||
break;
|
||||
case TGL_LOGIC_OP_MODE:
|
||||
error("gl_get_pname: TGL_LOGIC_OP_MODE option not implemented");
|
||||
break;
|
||||
case TGL_MAP1_COLOR_4:
|
||||
// fall through
|
||||
case TGL_MAP1_GRID_DOMAIN:
|
||||
// fall through
|
||||
case TGL_MAP1_GRID_SEGMENTS:
|
||||
// fall through
|
||||
case TGL_MAP1_INDEX:
|
||||
// fall through
|
||||
case TGL_MAP1_NORMAL:
|
||||
// fall through
|
||||
case TGL_MAP1_TEXTURE_COORD_1:
|
||||
// fall through
|
||||
case TGL_MAP1_TEXTURE_COORD_2:
|
||||
// fall through
|
||||
case TGL_MAP1_TEXTURE_COORD_3:
|
||||
// fall through
|
||||
case TGL_MAP1_TEXTURE_COORD_4:
|
||||
// fall through
|
||||
case TGL_MAP1_VERTEX_3:
|
||||
// fall through
|
||||
case TGL_MAP1_VERTEX_4:
|
||||
// fall through
|
||||
case TGL_MAP2_COLOR_4:
|
||||
// fall through
|
||||
case TGL_MAP2_GRID_DOMAIN:
|
||||
// fall through
|
||||
case TGL_MAP2_GRID_SEGMENTS:
|
||||
// fall through
|
||||
case TGL_MAP2_INDEX:
|
||||
// fall through
|
||||
case TGL_MAP2_NORMAL:
|
||||
// fall through
|
||||
case TGL_MAP2_TEXTURE_COORD_1:
|
||||
// fall through
|
||||
case TGL_MAP2_TEXTURE_COORD_2:
|
||||
// fall through
|
||||
case TGL_MAP2_TEXTURE_COORD_3:
|
||||
// fall through
|
||||
case TGL_MAP2_TEXTURE_COORD_4:
|
||||
// fall through
|
||||
case TGL_MAP2_VERTEX_3:
|
||||
// fall through
|
||||
case TGL_MAP2_VERTEX_4:
|
||||
error("gl_get_pname: TGL_MAPx option not implemented");
|
||||
break;
|
||||
case TGL_MAP_COLOR:
|
||||
// fall through
|
||||
case TGL_MAP_STENCIL:
|
||||
error("gl_get_pname: TGL_MAP_x not supported");
|
||||
break;
|
||||
case TGL_MATRIX_MODE:
|
||||
data->_int = matrix_mode;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_ATTRIB_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_MAX_ATTRIB_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_MAX_CLIENT_ATTRIB_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_MAX_CLIP_PLANES:
|
||||
error("gl_get_pname: TGL_MAX_CLIP_PLANES option not implemented");
|
||||
break;
|
||||
case TGL_MAX_ELEMENTS_INDICES:
|
||||
// fall through
|
||||
case TGL_MAX_ELEMENTS_VERTICES:
|
||||
error("gl_get_pname: TGL_MAX_ELEMENTS_x option not implemented");
|
||||
break;
|
||||
case TGL_MAX_EVAL_ORDER:
|
||||
error("gl_get_pname: TGL_MAX_EVAL_ORDER option not implemented");
|
||||
break;
|
||||
case TGL_MAX_LIGHTS:
|
||||
data->_int = T_MAX_LIGHTS;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_LIST_NESTING:
|
||||
error("gl_get_pname: TGL_MAX_LIST_NESTING option not implemented");
|
||||
break;
|
||||
case TGL_MAX_MODELVIEW_STACK_DEPTH:
|
||||
data->_int = MAX_MODELVIEW_STACK_DEPTH;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_NAME_STACK_DEPTH:
|
||||
data->_int = MAX_NAME_STACK_DEPTH;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_PIXEL_MAP_TABLE:
|
||||
error("gl_get_pname: TGL_MAX_PIXEL_MAP_TABLE option not implemented");
|
||||
break;
|
||||
case TGL_MAX_PROJECTION_STACK_DEPTH:
|
||||
data->_int = MAX_PROJECTION_STACK_DEPTH;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_TEXTURE_SIZE:
|
||||
data->_int = _textureSize;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_TEXTURE_STACK_DEPTH:
|
||||
data->_int = MAX_TEXTURE_STACK_DEPTH;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_MAX_VIEWPORT_DIMS:
|
||||
error("gl_get_pname: TGL_MAX_VIEWPORT_DIMS option not implemented");
|
||||
break;
|
||||
case TGL_TEXTURE_MATRIX:
|
||||
mnr++;
|
||||
// fall through
|
||||
case TGL_PROJECTION_MATRIX:
|
||||
mnr++;
|
||||
// fall through
|
||||
case TGL_MODELVIEW_MATRIX: {
|
||||
float *p = &matrix_stack_ptr[mnr]->_m[0][0];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data->_float16[i * 4 + 0] = p[0];
|
||||
data->_float16[i * 4 + 1] = p[4];
|
||||
data->_float16[i * 4 + 2] = p[8];
|
||||
data->_float16[i * 4 + 3] = p[12];
|
||||
p++;
|
||||
}
|
||||
}
|
||||
dataType = kFloat16Type;
|
||||
break;
|
||||
case TGL_MODELVIEW_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_MODELVIEW_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_NAME_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_NAME_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_NORMALIZE:
|
||||
data->_int = 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_NORMAL_ARRAY:
|
||||
data->_int = (TGLint)(normal_array != nullptr);
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_NORMAL_ARRAY_STRIDE:
|
||||
data->_int = normal_array_stride;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_NORMAL_ARRAY_TYPE:
|
||||
data->_int = normal_array_type;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_PACK_ALIGNMENT:
|
||||
// fall through
|
||||
case TGL_PACK_LSB_FIRST:
|
||||
// fall through
|
||||
case TGL_PACK_ROW_LENGTH:
|
||||
// fall through
|
||||
case TGL_PACK_SKIP_PIXELS:
|
||||
// fall through
|
||||
case TGL_PACK_SKIP_ROWS:
|
||||
// fall through
|
||||
case TGL_PACK_SWAP_BYTES:
|
||||
error("gl_get_pname: TGL_PACK_x option not implemented");
|
||||
break;
|
||||
case TGL_PERSPECTIVE_CORRECTION_HINT:
|
||||
data->_int = TGL_DONT_CARE;
|
||||
break;
|
||||
case TGL_PIXEL_MAP_A_TO_A_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_B_TO_B_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_G_TO_G_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_I_TO_A_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_I_TO_B_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_I_TO_G_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_I_TO_I_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_I_TO_R_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_R_TO_R_SIZE:
|
||||
// fall through
|
||||
case TGL_PIXEL_MAP_S_TO_S_SIZE:
|
||||
error("gl_get_pname: TGL_PIXEL_MAP_x option not implemented");
|
||||
break;
|
||||
case TGL_POINT_SIZE:
|
||||
// fall through
|
||||
case TGL_POINT_SIZE_GRANULARITY:
|
||||
// fall through
|
||||
case TGL_POINT_SIZE_RANGE:
|
||||
// fall through
|
||||
case TGL_POINT_SMOOTH:
|
||||
// fall through
|
||||
case TGL_POINT_SMOOTH_HINT:
|
||||
error("gl_get_pname: TGL_POINT_x option not implemented");
|
||||
break;
|
||||
case TGL_POLYGON_MODE:
|
||||
data->_float2[0] = polygon_mode_front;
|
||||
data->_float2[1] = polygon_mode_back;
|
||||
dataType = kFloat2Type;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_FACTOR:
|
||||
data->_float = offset_factor;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_FILL:
|
||||
data->_int = (offset_states & TGL_OFFSET_FILL) != 0 ? 1 : 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_LINE:
|
||||
data->_int = (offset_states & TGL_OFFSET_LINE) != 0 ? 1 : 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_POINT:
|
||||
data->_int = (offset_states & TGL_OFFSET_POINT) != 0 ? 1 : 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_UNITS:
|
||||
data->_float = offset_units;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_POLYGON_SMOOTH:
|
||||
// fall through
|
||||
case TGL_POLYGON_SMOOTH_HINT:
|
||||
error("gl_get_pname: TGL_POLYGON_SMOOTHx option not implemented");
|
||||
break;
|
||||
case TGL_POLYGON_STIPPLE:
|
||||
error("gl_get_pname: TGL_POLYGON_STIPPLE option not implemented");
|
||||
break;
|
||||
case TGL_PROJECTION_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_PROJECTION_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_READ_BUFFER:
|
||||
error("gl_get_pname: TGL_READ_BUFFER option not implemented");
|
||||
break;
|
||||
case TGL_RENDER_MODE:
|
||||
error("gl_get_pname: TGL_RENDER_MODE option not implemented");
|
||||
break;
|
||||
case TGL_RGBA_MODE:
|
||||
data->_int = 1;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_SCISSOR_BOX:
|
||||
data->_int4[0] = scissor[0];
|
||||
data->_int4[1] = scissor[1];
|
||||
data->_int4[2] = scissor[2];
|
||||
data->_int4[3] = scissor[3];
|
||||
dataType = kInt4Type;
|
||||
break;
|
||||
case TGL_SCISSOR_TEST:
|
||||
data->_int = (TGLint)scissor_test_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_SELECTION_BUFFER_SIZE:
|
||||
error("gl_get_pname: TGL_SELECTION_BUFFER_SIZE option not implemented");
|
||||
break;
|
||||
case TGL_SHADE_MODEL:
|
||||
data->_int = current_shade_model;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_BITS:
|
||||
data->_int = (TGLint)stencil_buffer_supported;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_CLEAR_VALUE:
|
||||
data->_float = clear_stencil;
|
||||
dataType = kFloatType;
|
||||
break;
|
||||
case TGL_STENCIL_FAIL:
|
||||
data->_int = (TGLint)stencil_sfail;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_FUNC:
|
||||
data->_int = (TGLint)stencil_test_func;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_PASS_DEPTH_FAIL:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_PASS_DEPTH_PASS:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_REF:
|
||||
data->_int = (TGLint)stencil_ref_val;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_TEST:
|
||||
data->_int = (TGLint)stencil_test_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_VALUE_MASK:
|
||||
data->_int = (TGLint)stencil_mask;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_STENCIL_WRITEMASK:
|
||||
data->_int = (TGLint)stencil_write_mask;
|
||||
dataType = kUintType;
|
||||
break;
|
||||
case TGL_STEREO:
|
||||
data->_int = (TGLint)TGL_FALSE;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_SUBPIXEL_BITS:
|
||||
error("gl_get_pname: TGL_SUBPIXEL_BITS option not implemented");
|
||||
break;
|
||||
case TGL_TEXTURE_1D:
|
||||
error("gl_get_pname: TGL_TEXTURE_1D option not implemented");
|
||||
break;
|
||||
case TGL_TEXTURE_2D:
|
||||
data->_int = (TGLint)texture_2d_enabled;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_TEXTURE_BINDING_1D:
|
||||
// fall through
|
||||
case TGL_TEXTURE_BINDING_2D:
|
||||
// fall through
|
||||
case TGL_TEXTURE_BINDING_3D:
|
||||
error("gl_get_pname: TGL_TEXTURE_BINDING_x option not implemented");
|
||||
break;
|
||||
case TGL_TEXTURE_COORD_ARRAY:
|
||||
data->_int = (texcoord_array != nullptr) ? 1 : 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_TEXTURE_COORD_ARRAY_SIZE:
|
||||
data->_int = texcoord_array_size;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_TEXTURE_COORD_ARRAY_STRIDE:
|
||||
data->_int = texcoord_array_stride;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_TEXTURE_COORD_ARRAY_TYPE:
|
||||
data->_int = texcoord_array_type;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_TEXTURE_GEN_Q:
|
||||
// fall through
|
||||
case TGL_TEXTURE_GEN_R:
|
||||
// fall through
|
||||
case TGL_TEXTURE_GEN_S:
|
||||
// fall through
|
||||
case TGL_TEXTURE_GEN_T:
|
||||
error("gl_get_pname: TGL_TEXTURE_GEN_x option not implemented");
|
||||
break;
|
||||
case TGL_TEXTURE_STACK_DEPTH:
|
||||
error("gl_get_pname: TGL_TEXTURE_STACK_DEPTH option not implemented");
|
||||
break;
|
||||
case TGL_UNPACK_ALIGNMENT:
|
||||
// fall through
|
||||
case TGL_UNPACK_LSB_FIRST:
|
||||
// fall through
|
||||
case TGL_UNPACK_ROW_LENGTH:
|
||||
// fall through
|
||||
case TGL_UNPACK_SKIP_IMAGES:
|
||||
// fall through
|
||||
case TGL_UNPACK_SKIP_PIXELS:
|
||||
// fall through
|
||||
case TGL_UNPACK_SKIP_ROWS:
|
||||
// fall through
|
||||
case TGL_UNPACK_SWAP_BYTES:
|
||||
error("gl_get_pname: TGL_UNPACK_x option not implemented");
|
||||
break;
|
||||
case TGL_VERTEX_ARRAY:
|
||||
data->_int = (vertex_array != nullptr) ? 1 : 0;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_VERTEX_ARRAY_SIZE:
|
||||
data->_int = vertex_array_size;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_VERTEX_ARRAY_STRIDE:
|
||||
data->_int = vertex_array_stride;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_VERTEX_ARRAY_TYPE:
|
||||
data->_int = vertex_array_type;
|
||||
dataType = kIntType;
|
||||
break;
|
||||
case TGL_VIEWPORT:
|
||||
data->_int4[0] = viewport.xmin;
|
||||
data->_int4[1] = viewport.ymin;
|
||||
data->_int4[2] = viewport.xsize;
|
||||
data->_int4[3] = viewport.ysize;
|
||||
dataType = kInt4Type;
|
||||
break;
|
||||
case TGL_ZOOM_X:
|
||||
// fall through
|
||||
case TGL_ZOOM_Y:
|
||||
error("gl_get_pname: TGL_ZOOM_x option not implemented");
|
||||
break;
|
||||
default:
|
||||
error("gl_get_pname: unknown option");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_GetIntegerv(TGLenum pname, TGLint *data) {
|
||||
eDataType dataType;
|
||||
union uglValue tmpData;
|
||||
|
||||
gl_get_pname(pname, &tmpData, dataType);
|
||||
|
||||
switch (dataType) {
|
||||
case kIntType:
|
||||
data[0] = tmpData._int;
|
||||
break;
|
||||
case kInt4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = tmpData._int4[i];
|
||||
break;
|
||||
case kUintType:
|
||||
data[0] = tmpData._int;
|
||||
break;
|
||||
case kFloatType:
|
||||
data[0] = FLOAT_TO_INTEGER(tmpData._float);
|
||||
break;
|
||||
case kFloat2Type:
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = FLOAT_TO_INTEGER(tmpData._float2[i]);
|
||||
break;
|
||||
case kFloat4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = FLOAT_TO_INTEGER(tmpData._float4[i]);
|
||||
break;
|
||||
case kFloat16Type:
|
||||
for (int i = 0; i < 16; i++)
|
||||
data[i] = FLOAT_TO_INTEGER(tmpData._float16[i]);
|
||||
break;
|
||||
default:
|
||||
assert("gl_GetIntegerv: unknown data type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_GetFloatv(TGLenum pname, TGLfloat *data) {
|
||||
eDataType dataType;
|
||||
union uglValue tmpData;
|
||||
|
||||
gl_get_pname(pname, &tmpData, dataType);
|
||||
|
||||
switch (dataType) {
|
||||
case kIntType:
|
||||
data[0] = tmpData._int;
|
||||
break;
|
||||
case kInt4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = tmpData._int4[i];
|
||||
break;
|
||||
case kUintType:
|
||||
data[0] = (TGLuint)tmpData._int;
|
||||
break;
|
||||
case kFloatType:
|
||||
data[0] = tmpData._float;
|
||||
break;
|
||||
case kFloat2Type:
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = tmpData._float2[i];
|
||||
break;
|
||||
case kFloat4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = tmpData._float4[i];
|
||||
break;
|
||||
case kFloat16Type:
|
||||
for (int i = 0; i < 16; i++)
|
||||
data[i] = tmpData._float16[i];
|
||||
break;
|
||||
default:
|
||||
assert("gl_GetFloatv: unknown data type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_GetDoublev(TGLenum pname, TGLdouble *data) {
|
||||
eDataType dataType;
|
||||
union uglValue tmpData;
|
||||
|
||||
gl_get_pname(pname, &tmpData, dataType);
|
||||
|
||||
switch (dataType) {
|
||||
case kIntType:
|
||||
data[0] = tmpData._int;
|
||||
break;
|
||||
case kInt4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = tmpData._int4[i];
|
||||
break;
|
||||
case kUintType:
|
||||
data[0] = (TGLuint)tmpData._int;
|
||||
break;
|
||||
case kFloatType:
|
||||
data[0] = tmpData._float;
|
||||
break;
|
||||
case kFloat2Type:
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = tmpData._float2[i];
|
||||
break;
|
||||
case kFloat4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = tmpData._float4[i];
|
||||
break;
|
||||
case kFloat16Type:
|
||||
for (int i = 0; i < 16; i++)
|
||||
data[i] = tmpData._float16[i];
|
||||
break;
|
||||
default:
|
||||
assert("gl_GetDoublev: unknown data type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_GetBooleanv(TGLenum pname, TGLboolean *data) {
|
||||
eDataType dataType;
|
||||
union uglValue tmpData;
|
||||
|
||||
gl_get_pname(pname, &tmpData, dataType);
|
||||
|
||||
switch (dataType) {
|
||||
case kIntType:
|
||||
data[0] = VALUE_TO_BOOLEAN(tmpData._int);
|
||||
break;
|
||||
case kInt4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = VALUE_TO_BOOLEAN(tmpData._int4[i]);
|
||||
break;
|
||||
case kUintType:
|
||||
data[0] = VALUE_TO_BOOLEAN(tmpData._int);
|
||||
break;
|
||||
case kFloatType:
|
||||
data[0] = VALUE_TO_BOOLEAN(tmpData._float);
|
||||
break;
|
||||
case kFloat2Type:
|
||||
for (int i = 0; i < 2; i++)
|
||||
data[i] = VALUE_TO_BOOLEAN(tmpData._float2[i]);
|
||||
break;
|
||||
case kFloat4Type:
|
||||
for (int i = 0; i < 4; i++)
|
||||
data[i] = VALUE_TO_BOOLEAN(tmpData._float4[i]);
|
||||
break;
|
||||
case kFloat16Type:
|
||||
for (int i = 0; i < 16; i++)
|
||||
data[i] = VALUE_TO_BOOLEAN(tmpData._float16[i]);
|
||||
break;
|
||||
default:
|
||||
assert("gl_GetBooleanv: unknown data type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
1210
graphics/tinygl/gl.h
Normal file
1210
graphics/tinygl/gl.h
Normal file
File diff suppressed because it is too large
Load Diff
377
graphics/tinygl/init.cpp
Normal file
377
graphics/tinygl/init.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "common/singleton.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "graphics/tinygl/tinygl.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/zblit.h"
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
class GLContextArray : public Common::Singleton<GLContextArray> {
|
||||
private:
|
||||
|
||||
Common::Array<GLContext *> _glContextArray;
|
||||
|
||||
public:
|
||||
|
||||
GLContext *createContext() {
|
||||
GLContext *ctx = new GLContext;
|
||||
_glContextArray.push_back(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void destroyContext(ContextHandle *handle) {
|
||||
for (Common::Array<GLContext *>::iterator it = _glContextArray.begin(); it != _glContextArray.end(); it++) {
|
||||
if (*it == (GLContext *)handle) {
|
||||
(*it)->deinit();
|
||||
delete *it;
|
||||
_glContextArray.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroyContexts() {
|
||||
for (Common::Array<GLContext *>::iterator it = _glContextArray.begin(); it != _glContextArray.end(); it++) {
|
||||
if (*it != nullptr) {
|
||||
(*it)->deinit();
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
_glContextArray.clear();
|
||||
}
|
||||
|
||||
bool existsContexts() {
|
||||
return _glContextArray.size() != 0;
|
||||
}
|
||||
|
||||
GLContext *getContext(ContextHandle *handle) {
|
||||
for (Common::Array<GLContext *>::iterator it = _glContextArray.begin(); it != _glContextArray.end(); it++) {
|
||||
if ((*it) == (GLContext *)handle) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(TinyGL::GLContextArray);
|
||||
}
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
GLContext *gl_ctx;
|
||||
|
||||
GLContext *gl_get_context() {
|
||||
assert(gl_ctx);
|
||||
return gl_ctx;
|
||||
}
|
||||
|
||||
ContextHandle *createContext(int screenW, int screenH, Graphics::PixelFormat pixelFormat, int textureSize,
|
||||
bool enableStencilBuffer, bool dirtyRectsEnable, uint32 drawCallMemorySize) {
|
||||
gl_ctx = GLContextArray::instance().createContext();
|
||||
gl_ctx->init(screenW, screenH, pixelFormat, textureSize, enableStencilBuffer,
|
||||
dirtyRectsEnable, drawCallMemorySize);
|
||||
return (ContextHandle *)gl_ctx;
|
||||
}
|
||||
|
||||
void destroyContext() {
|
||||
GLContextArray::instance().destroyContexts();
|
||||
GLContextArray::destroy();
|
||||
gl_ctx = nullptr;
|
||||
}
|
||||
|
||||
void destroyContext(ContextHandle *handle) {
|
||||
GLContextArray::instance().destroyContext(handle);
|
||||
if ((GLContext *)handle == gl_ctx)
|
||||
gl_ctx = nullptr;
|
||||
if (!GLContextArray::instance().existsContexts())
|
||||
GLContextArray::destroy();
|
||||
}
|
||||
|
||||
void setContext(ContextHandle *handle) {
|
||||
GLContext *ctx = GLContextArray::instance().getContext(handle);
|
||||
if (ctx == nullptr) {
|
||||
error("TinyGL: makeContextCurrent() Failed get context");
|
||||
}
|
||||
gl_ctx = ctx;
|
||||
}
|
||||
|
||||
void GLContext::initSharedState() {
|
||||
GLSharedState *s = &shared_state;
|
||||
s->lists = (GLList **)gl_zalloc(sizeof(GLList *) * MAX_DISPLAY_LISTS);
|
||||
s->texture_hash_table = (GLTexture **)gl_zalloc(sizeof(GLTexture *) * TEXTURE_HASH_TABLE_SIZE);
|
||||
}
|
||||
|
||||
void GLContext::endSharedState() {
|
||||
GLSharedState *s = &shared_state;
|
||||
|
||||
for (int i = 0; i < MAX_DISPLAY_LISTS; i++) {
|
||||
// TODO
|
||||
}
|
||||
gl_free(s->lists);
|
||||
|
||||
gl_free(s->texture_hash_table);
|
||||
}
|
||||
|
||||
void GLContext::init(int screenW, int screenH, Graphics::PixelFormat pixelFormat, int textureSize,
|
||||
bool enableStencilBuffer, bool dirtyRectsEnable, uint32 drawCallMemorySize) {
|
||||
GLViewport *v;
|
||||
|
||||
_enableDirtyRectangles = dirtyRectsEnable;
|
||||
stencil_buffer_supported = enableStencilBuffer;
|
||||
|
||||
fb = new TinyGL::FrameBuffer(screenW, screenH, pixelFormat, enableStencilBuffer);
|
||||
renderRect = Common::Rect(0, 0, screenW, screenH);
|
||||
|
||||
if ((textureSize & (textureSize - 1)))
|
||||
error("glInit: texture size not power of two: %d", textureSize);
|
||||
if (textureSize <= 1 || textureSize > 4096)
|
||||
error("glInit: texture size not allowed: %d", textureSize);
|
||||
_textureSize = textureSize;
|
||||
fb->setTextureSizeAndMask(textureSize, (textureSize - 1) << ZB_POINT_ST_FRAC_BITS);
|
||||
fb->setTextureEnvironment(&_texEnv);
|
||||
|
||||
// allocate GLVertex array
|
||||
vertex_max = POLYGON_MAX_VERTEX;
|
||||
vertex = (GLVertex *)gl_malloc(POLYGON_MAX_VERTEX * sizeof(GLVertex));
|
||||
|
||||
// viewport
|
||||
v = &viewport;
|
||||
v->xmin = 0;
|
||||
v->ymin = 0;
|
||||
v->xsize = screenW;
|
||||
v->ysize = screenH;
|
||||
v->updated = 1;
|
||||
|
||||
// shared state
|
||||
initSharedState();
|
||||
|
||||
// lists
|
||||
exec_flag = 1;
|
||||
compile_flag = 0;
|
||||
print_flag = 0;
|
||||
|
||||
in_begin = 0;
|
||||
|
||||
// lights
|
||||
for (int i = 0; i < T_MAX_LIGHTS; i++) {
|
||||
GLLight *l = &lights[i];
|
||||
l->ambient = Vector4(0, 0, 0, 1);
|
||||
if (i == 0) {
|
||||
l->diffuse = Vector4(1, 1, 1, 1);
|
||||
l->specular = Vector4(1, 1, 1, 1);
|
||||
l->has_specular = true;
|
||||
} else {
|
||||
l->diffuse = Vector4(0, 0, 0, 1);
|
||||
l->specular = Vector4(0, 0, 0, 1);
|
||||
l->has_specular = false;
|
||||
}
|
||||
l->position = Vector4(0, 0, 1, 0);
|
||||
l->spot_direction = Vector3(0, 0, -1);
|
||||
l->spot_exponent = 0;
|
||||
l->spot_cutoff = 180;
|
||||
l->attenuation[0] = 1;
|
||||
l->attenuation[1] = 0;
|
||||
l->attenuation[2] = 0;
|
||||
l->cos_spot_cutoff = -1.0f;
|
||||
l->norm_spot_direction = Vector3(0, 0, -1);
|
||||
l->norm_position = Vector3(0, 0, 1);
|
||||
l->enabled = 0;
|
||||
l->next = nullptr;
|
||||
l->prev = nullptr;
|
||||
}
|
||||
first_light = nullptr;
|
||||
ambient_light_model = Vector4(0.2f, 0.2f, 0.2f, 1);
|
||||
local_light_model = 0;
|
||||
lighting_enabled = 0;
|
||||
light_model_two_side = 0;
|
||||
|
||||
// default materials */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
GLMaterial *m = &materials[i];
|
||||
m->emission = Vector4(0, 0, 0, 1);
|
||||
m->ambient = Vector4(0.2f, 0.2f, 0.2f, 1);
|
||||
m->diffuse = Vector4(0.8f, 0.8f, 0.8f, 1);
|
||||
m->specular = Vector4(0, 0, 0, 1);
|
||||
m->has_specular = false;
|
||||
m->shininess = 0;
|
||||
}
|
||||
current_color_material_mode = TGL_FRONT_AND_BACK;
|
||||
current_color_material_type = TGL_AMBIENT_AND_DIFFUSE;
|
||||
color_material_enabled = 0;
|
||||
|
||||
// textures
|
||||
texture_2d_enabled = false;
|
||||
current_texture = default_texture = alloc_texture(0);
|
||||
maxTextureName = 0;
|
||||
texture_mag_filter = TGL_LINEAR;
|
||||
texture_min_filter = TGL_NEAREST_MIPMAP_LINEAR;
|
||||
colorAssociationList.push_back({Graphics::PixelFormat::createFormatRGBA32(), TGL_RGBA, TGL_UNSIGNED_BYTE});
|
||||
colorAssociationList.push_back({Graphics::PixelFormat::createFormatRGB24(), TGL_RGB, TGL_UNSIGNED_BYTE});
|
||||
colorAssociationList.push_back({Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), TGL_RGB, TGL_UNSIGNED_SHORT_5_6_5});
|
||||
colorAssociationList.push_back({Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), TGL_RGBA, TGL_UNSIGNED_SHORT_5_5_5_1});
|
||||
colorAssociationList.push_back({Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), TGL_RGBA, TGL_UNSIGNED_SHORT_4_4_4_4});
|
||||
|
||||
// default state
|
||||
current_color = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
current_normal = Vector4(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
current_edge_flag = 1;
|
||||
|
||||
current_tex_coord = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
polygon_mode_front = TGL_FILL;
|
||||
polygon_mode_back = TGL_FILL;
|
||||
|
||||
current_front_face = 0; // 0 = GL_CCW 1 = GL_CW
|
||||
current_cull_face = TGL_BACK;
|
||||
current_shade_model = TGL_SMOOTH;
|
||||
cull_face_enabled = 0;
|
||||
|
||||
// scissor
|
||||
scissor_test_enabled = false;
|
||||
scissor[0] = scissor[1] = 0;
|
||||
scissor[2] = screenW;
|
||||
scissor[3] = screenH;
|
||||
|
||||
// fog
|
||||
fog_enabled = false;
|
||||
fog_mode = TGL_EXP;
|
||||
fog_color = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
fog_density = 1.0f;
|
||||
fog_start = 0.0f;
|
||||
fog_end = 0.0f;
|
||||
|
||||
// clear
|
||||
clear_color = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
clear_depth = 1.0f;
|
||||
clear_stencil = 0;
|
||||
|
||||
// selection
|
||||
render_mode = TGL_RENDER;
|
||||
select_buffer = nullptr;
|
||||
name_stack_size = 0;
|
||||
|
||||
// blending
|
||||
blending_enabled = false;
|
||||
source_blending_factor = TGL_ONE;
|
||||
destination_blending_factor = TGL_ZERO;
|
||||
|
||||
// alpha test
|
||||
alpha_test_enabled = false;
|
||||
alpha_test_func = TGL_ALWAYS;
|
||||
alpha_test_ref_val = 0;
|
||||
|
||||
// depth test
|
||||
depth_test_enabled = false;
|
||||
depth_func = TGL_LESS;
|
||||
depth_write_mask = true;
|
||||
|
||||
// stipple
|
||||
polygon_stipple_enabled = false;
|
||||
memset(polygon_stipple_pattern, 0xff, sizeof(polygon_stipple_pattern));
|
||||
|
||||
// stencil
|
||||
stencil_test_enabled = false;
|
||||
stencil_test_func = TGL_ALWAYS;
|
||||
stencil_ref_val = 0;
|
||||
stencil_mask = 0xff;
|
||||
stencil_write_mask = 0xff;
|
||||
stencil_sfail = TGL_KEEP;
|
||||
stencil_dpfail = TGL_KEEP;
|
||||
stencil_dppass = TGL_KEEP;
|
||||
|
||||
// matrix
|
||||
matrix_mode = 0;
|
||||
|
||||
matrix_stack_depth_max[0] = MAX_MODELVIEW_STACK_DEPTH;
|
||||
matrix_stack_depth_max[1] = MAX_PROJECTION_STACK_DEPTH;
|
||||
matrix_stack_depth_max[2] = MAX_TEXTURE_STACK_DEPTH;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
matrix_stack[i] = (Matrix4 *)gl_zalloc(matrix_stack_depth_max[i] * sizeof(Matrix4));
|
||||
matrix_stack_ptr[i] = matrix_stack[i];
|
||||
}
|
||||
|
||||
tglMatrixMode(TGL_PROJECTION);
|
||||
tglLoadIdentity();
|
||||
tglMatrixMode(TGL_TEXTURE);
|
||||
tglLoadIdentity();
|
||||
tglMatrixMode(TGL_MODELVIEW);
|
||||
tglLoadIdentity();
|
||||
|
||||
matrix_model_projection_updated = 1;
|
||||
|
||||
// opengl 1.1 arrays
|
||||
client_states = 0;
|
||||
|
||||
// opengl 1.1 polygon offset
|
||||
offset_states = 0;
|
||||
offset_factor = 0.0f;
|
||||
offset_units = 0.0f;
|
||||
|
||||
// clear the resize callback function pointer
|
||||
gl_resize_viewport = nullptr;
|
||||
|
||||
// specular buffer
|
||||
specbuf_first = nullptr;
|
||||
specbuf_used_counter = 0;
|
||||
specbuf_num_buffers = 0;
|
||||
|
||||
// color mask
|
||||
color_mask_red = color_mask_green = color_mask_blue = color_mask_alpha = true;
|
||||
|
||||
_currentAllocatorIndex = 0;
|
||||
_drawCallAllocator[0].initialize(drawCallMemorySize);
|
||||
_drawCallAllocator[1].initialize(drawCallMemorySize);
|
||||
_debugRectsEnabled = false;
|
||||
_profilingEnabled = false;
|
||||
}
|
||||
|
||||
void GLContext::deinit() {
|
||||
disposeDrawCallLists();
|
||||
disposeResources();
|
||||
|
||||
specbuf_cleanup();
|
||||
for (int i = 0; i < 3; i++)
|
||||
gl_free(matrix_stack[i]);
|
||||
free_texture(default_texture);
|
||||
endSharedState();
|
||||
gl_free(vertex);
|
||||
delete fb;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
318
graphics/tinygl/light.cpp
Normal file
318
graphics/tinygl/light.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopMaterial(GLParam *p) {
|
||||
int mode = p[1].i;
|
||||
int type = p[2].i;
|
||||
Vector4 v(p[3].f, p[4].f, p[5].f, p[6].f);
|
||||
GLMaterial *m;
|
||||
|
||||
if (mode == TGL_FRONT_AND_BACK) {
|
||||
p[1].i = TGL_FRONT;
|
||||
glopMaterial(p);
|
||||
mode = TGL_BACK;
|
||||
}
|
||||
if (mode == TGL_FRONT)
|
||||
m = &materials[0];
|
||||
else
|
||||
m = &materials[1];
|
||||
|
||||
switch (type) {
|
||||
case TGL_EMISSION:
|
||||
m->emission = v;
|
||||
break;
|
||||
case TGL_AMBIENT:
|
||||
m->ambient = v;
|
||||
break;
|
||||
case TGL_DIFFUSE:
|
||||
m->diffuse = v;
|
||||
break;
|
||||
case TGL_SPECULAR:
|
||||
m->specular = v;
|
||||
m->has_specular = v.X != 0 || v.Y != 0 || v.Z != 0 || v.W != 1;
|
||||
break;
|
||||
case TGL_SHININESS:
|
||||
m->shininess = v.X;
|
||||
m->shininess_i = (int)(v.X / 128.0f) * SPECULAR_BUFFER_RESOLUTION;
|
||||
break;
|
||||
case TGL_AMBIENT_AND_DIFFUSE:
|
||||
m->diffuse = v;
|
||||
m->ambient = v;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopColorMaterial(GLParam *p) {
|
||||
int mode = p[1].i;
|
||||
int type = p[2].i;
|
||||
|
||||
current_color_material_mode = mode;
|
||||
current_color_material_type = type;
|
||||
}
|
||||
|
||||
void GLContext::glopLight(GLParam *p) {
|
||||
int light = p[1].i;
|
||||
int type = p[2].i;
|
||||
Vector4 v(p[3].f, p[4].f, p[5].f, p[6].f);
|
||||
GLLight *l;
|
||||
|
||||
assert(light >= TGL_LIGHT0 && light < TGL_LIGHT0 + T_MAX_LIGHTS);
|
||||
|
||||
l = &lights[light - TGL_LIGHT0];
|
||||
|
||||
switch (type) {
|
||||
case TGL_AMBIENT:
|
||||
l->ambient = v;
|
||||
break;
|
||||
case TGL_DIFFUSE:
|
||||
l->diffuse = v;
|
||||
break;
|
||||
case TGL_SPECULAR:
|
||||
l->specular = v;
|
||||
l->has_specular = v.X != 0 || v.Y != 0 || v.Z != 0 || v.W != 1;
|
||||
break;
|
||||
case TGL_POSITION: {
|
||||
Vector4 pos;
|
||||
matrix_stack_ptr[0]->transform(v, pos);
|
||||
|
||||
l->position = pos;
|
||||
|
||||
if (l->position.W == 0) {
|
||||
l->norm_position.X = pos.X;
|
||||
l->norm_position.Y = pos.Y;
|
||||
l->norm_position.Z = pos.Z;
|
||||
l->norm_position.normalize();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TGL_SPOT_DIRECTION:
|
||||
l->spot_direction.X = v.X;
|
||||
l->spot_direction.Y = v.Y;
|
||||
l->spot_direction.Z = v.Z;
|
||||
matrix_stack_ptr[0]->transform3x3(l->spot_direction, l->norm_spot_direction);
|
||||
l->norm_spot_direction.normalize();
|
||||
break;
|
||||
case TGL_SPOT_EXPONENT:
|
||||
l->spot_exponent = v.X;
|
||||
break;
|
||||
case TGL_SPOT_CUTOFF: {
|
||||
float a = v.X;
|
||||
assert(a == 180 || (a >= 0 && a <= 90));
|
||||
l->spot_cutoff = a;
|
||||
if (a != 180)
|
||||
l->cos_spot_cutoff = (float)(cos(a * (float)M_PI / 180.0));
|
||||
}
|
||||
break;
|
||||
case TGL_CONSTANT_ATTENUATION:
|
||||
l->attenuation[0] = v.X;
|
||||
break;
|
||||
case TGL_LINEAR_ATTENUATION:
|
||||
l->attenuation[1] = v.X;
|
||||
break;
|
||||
case TGL_QUADRATIC_ATTENUATION:
|
||||
l->attenuation[2] = v.X;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopLightModel(GLParam *p) {
|
||||
int pname = p[1].i;
|
||||
|
||||
switch (pname) {
|
||||
case TGL_LIGHT_MODEL_AMBIENT:
|
||||
ambient_light_model = Vector4(p[2].f, p[3].f, p[4].f, p[5].f);
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_LOCAL_VIEWER:
|
||||
local_light_model = (int)p[2].f;
|
||||
break;
|
||||
case TGL_LIGHT_MODEL_TWO_SIDE:
|
||||
light_model_two_side = (int)p[2].f;
|
||||
break;
|
||||
default:
|
||||
warning("glopLightModel: illegal pname: 0x%x", pname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_enable_disable_light(int light, int v) {
|
||||
GLLight *l = &lights[light];
|
||||
if (v && !l->enabled) {
|
||||
l->enabled = 1;
|
||||
if (first_light != l) {
|
||||
l->next = first_light;
|
||||
if (first_light)
|
||||
first_light->prev = l;
|
||||
first_light = l;
|
||||
l->prev = nullptr;
|
||||
}
|
||||
} else if (!v && l->enabled) {
|
||||
l->enabled = 0;
|
||||
if (!l->prev)
|
||||
first_light = l->next;
|
||||
else
|
||||
l->prev->next = l->next;
|
||||
if (l->next)
|
||||
l->next->prev = l->prev;
|
||||
}
|
||||
}
|
||||
|
||||
// non optimized lightning model
|
||||
void GLContext::gl_shade_vertex(GLVertex *v) {
|
||||
float R, G, B, A;
|
||||
GLMaterial *m;
|
||||
GLLight *l;
|
||||
Vector3 n, s, d;
|
||||
float dist, tmp, att, dot, dot_spot, dot_spec;
|
||||
int twoside = light_model_two_side;
|
||||
|
||||
m = &materials[0];
|
||||
|
||||
n = v->normal;
|
||||
|
||||
R = m->emission.X + m->ambient.X * ambient_light_model.X;
|
||||
G = m->emission.Y + m->ambient.Y * ambient_light_model.Y;
|
||||
B = m->emission.Z + m->ambient.Z * ambient_light_model.Z;
|
||||
A = clampf(m->diffuse.W, 0, 1);
|
||||
|
||||
for (l = first_light; l != nullptr; l = l->next) {
|
||||
float lR, lB, lG;
|
||||
|
||||
// ambient
|
||||
lR = l->ambient.X * m->ambient.X;
|
||||
lG = l->ambient.Y * m->ambient.Y;
|
||||
lB = l->ambient.Z * m->ambient.Z;
|
||||
|
||||
if (l->position.W == 0) {
|
||||
// light at infinity
|
||||
d.X = l->norm_position.X;
|
||||
d.Y = l->norm_position.Y;
|
||||
d.Z = l->norm_position.Z;
|
||||
dist = 1;
|
||||
att = 1;
|
||||
} else {
|
||||
// distance attenuation
|
||||
d.X = l->position.X - v->ec.X;
|
||||
d.Y = l->position.Y - v->ec.Y;
|
||||
d.Z = l->position.Z - v->ec.Z;
|
||||
dist = sqrt(d.X * d.X + d.Y * d.Y + d.Z * d.Z);
|
||||
att = 1.0f / (l->attenuation[0] +
|
||||
dist * (l->attenuation[1] +
|
||||
dist * l->attenuation[2]));
|
||||
}
|
||||
dot = d.X * n.X + d.Y * n.Y + d.Z * n.Z;
|
||||
if (twoside && dot < 0)
|
||||
dot = -dot;
|
||||
if (dot > 0) {
|
||||
tmp = 1 / dist;
|
||||
d *= tmp;
|
||||
dot *= tmp;
|
||||
// diffuse light
|
||||
lR += dot * l->diffuse.X * m->diffuse.X;
|
||||
lG += dot * l->diffuse.Y * m->diffuse.Y;
|
||||
lB += dot * l->diffuse.Z * m->diffuse.Z;
|
||||
|
||||
const bool is_spotlight = l->spot_cutoff != 180;
|
||||
const bool has_specular = l->has_specular && m->has_specular;
|
||||
if (is_spotlight || has_specular) {
|
||||
if (is_spotlight) {
|
||||
dot_spot = -(d.X * l->norm_spot_direction.X +
|
||||
d.Y * l->norm_spot_direction.Y +
|
||||
d.Z * l->norm_spot_direction.Z);
|
||||
if (twoside && dot_spot < 0)
|
||||
dot_spot = -dot_spot;
|
||||
if (dot_spot < l->cos_spot_cutoff) {
|
||||
// no contribution
|
||||
continue;
|
||||
} else {
|
||||
// TODO: optimize
|
||||
if (l->spot_exponent > 0) {
|
||||
att = att * pow(dot_spot, l->spot_exponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_specular) {
|
||||
if (local_light_model) {
|
||||
Vector3 vcoord;
|
||||
vcoord.X = v->ec.X;
|
||||
vcoord.Y = v->ec.Y;
|
||||
vcoord.Z = v->ec.Z;
|
||||
vcoord.normalize();
|
||||
s.X = d.X - vcoord.X;
|
||||
s.Y = d.Y - vcoord.Y;
|
||||
s.Z = d.Z - vcoord.Z;
|
||||
} else {
|
||||
s.X = d.X;
|
||||
s.Y = d.Y;
|
||||
s.Z = (float)(d.Z + 1.0);
|
||||
}
|
||||
dot_spec = n.X * s.X + n.Y * s.Y + n.Z * s.Z;
|
||||
if (twoside && dot_spec < 0)
|
||||
dot_spec = -dot_spec;
|
||||
if (dot_spec > 0) {
|
||||
GLSpecBuf *specbuf;
|
||||
int idx;
|
||||
dot_spec = dot_spec / sqrt(s.X * s.X + s.Y * s.Y + s.Z * s.Z);
|
||||
// TODO: optimize
|
||||
// testing specular buffer code
|
||||
// dot_spec= pow(dot_spec,m->shininess)
|
||||
specbuf = specbuf_get_buffer(m->shininess_i, m->shininess);
|
||||
tmp = dot_spec * SPECULAR_BUFFER_SIZE;
|
||||
if (tmp > SPECULAR_BUFFER_SIZE)
|
||||
idx = SPECULAR_BUFFER_SIZE;
|
||||
else
|
||||
idx = (int)tmp;
|
||||
|
||||
dot_spec = specbuf->buf[idx];
|
||||
lR += dot_spec * l->specular.X * m->specular.X;
|
||||
lG += dot_spec * l->specular.Y * m->specular.Y;
|
||||
lB += dot_spec * l->specular.Z * m->specular.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R += att * lR;
|
||||
G += att * lG;
|
||||
B += att * lB;
|
||||
}
|
||||
|
||||
v->color.X = clampf(R, 0, 1);
|
||||
v->color.Y = clampf(G, 0, 1);
|
||||
v->color.Z = clampf(B, 0, 1);
|
||||
v->color.W = A;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
244
graphics/tinygl/list.cpp
Normal file
244
graphics/tinygl/list.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "common/streamdebug.h"
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
#define ADD_OP(aa, bb, ff) \
|
||||
static void glop ## aa (GLContext *c, GLParam *p) { \
|
||||
c->glop ## aa (p); \
|
||||
}
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
|
||||
static const char *const op_table_str[] = {
|
||||
#define ADD_OP(a, b, c) "gl" #a " " #c,
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
};
|
||||
|
||||
static void (*const op_table_func[])(GLContext *, GLParam *) = {
|
||||
#define ADD_OP(a, b, c) glop ## a ,
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
};
|
||||
|
||||
static const int op_table_size[] = {
|
||||
#define ADD_OP(a, b, c) b + 1 ,
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
};
|
||||
|
||||
GLList *GLContext::find_list(uint list) {
|
||||
return shared_state.lists[list];
|
||||
}
|
||||
|
||||
void GLContext::delete_list(int list) {
|
||||
GLList *l = find_list(list);
|
||||
assert(l);
|
||||
|
||||
// free param buffer
|
||||
GLParamBuffer *pb = l->first_op_buffer;
|
||||
while (pb) {
|
||||
GLParamBuffer *pb1 = pb->next;
|
||||
gl_free(pb);
|
||||
pb = pb1;
|
||||
}
|
||||
|
||||
gl_free(l);
|
||||
shared_state.lists[list] = nullptr;
|
||||
}
|
||||
|
||||
GLList *GLContext::alloc_list(int list) {
|
||||
GLList *l = (GLList *)gl_zalloc(sizeof(GLList));
|
||||
GLParamBuffer *ob = (GLParamBuffer *)gl_zalloc(sizeof(GLParamBuffer));
|
||||
|
||||
ob->next = nullptr;
|
||||
l->first_op_buffer = ob;
|
||||
|
||||
ob->ops[0].op = OP_EndList;
|
||||
|
||||
shared_state.lists[list] = l;
|
||||
return l;
|
||||
}
|
||||
|
||||
static void gl_print_op(GLParam *p) {
|
||||
Common::StreamDebug debug = streamDbg();
|
||||
int op = p[0].op;
|
||||
|
||||
p++;
|
||||
const char *s = op_table_str[op];
|
||||
while (*s != 0) {
|
||||
if (*s == '%') {
|
||||
s++;
|
||||
switch (*s++) {
|
||||
case 'f':
|
||||
debug << p[0].f;
|
||||
break;
|
||||
default:
|
||||
debug << p[0].i;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
} else {
|
||||
debug << *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
debug << "\n";
|
||||
}
|
||||
|
||||
void GLContext::gl_compile_op(GLParam *p) {
|
||||
int op = p[0].op;
|
||||
int op_size = op_table_size[op];
|
||||
int index = current_op_buffer_index;
|
||||
GLParamBuffer *ob = current_op_buffer;
|
||||
|
||||
// we should be able to add a NextBuffer opcode
|
||||
if ((index + op_size) > (OP_BUFFER_MAX_SIZE - 2)) {
|
||||
|
||||
GLParamBuffer *ob1 = (GLParamBuffer *)gl_zalloc(sizeof(GLParamBuffer));
|
||||
ob1->next = nullptr;
|
||||
|
||||
ob->next = ob1;
|
||||
ob->ops[index].op = OP_NextBuffer;
|
||||
ob->ops[index + 1].p = (void *)ob1;
|
||||
|
||||
current_op_buffer = ob1;
|
||||
ob = ob1;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < op_size; i++) {
|
||||
ob->ops[index] = p[i];
|
||||
index++;
|
||||
}
|
||||
current_op_buffer_index = index;
|
||||
}
|
||||
|
||||
void GLContext::gl_add_op(GLParam *p) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int op = p[0].op;
|
||||
if (exec_flag) {
|
||||
op_table_func[op](c, p);
|
||||
}
|
||||
if (compile_flag) {
|
||||
gl_compile_op(p);
|
||||
}
|
||||
if (print_flag) {
|
||||
gl_print_op(p);
|
||||
}
|
||||
}
|
||||
|
||||
// this opcode is never called directly
|
||||
void GLContext::glopEndList(GLParam *) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// this opcode is never called directly
|
||||
void GLContext::glopNextBuffer(GLParam *) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void GLContext::glopCallList(GLParam *p) {
|
||||
uint list = p[1].ui;
|
||||
GLList *l = find_list(list);
|
||||
|
||||
if (!l)
|
||||
error("list %d not defined", list);
|
||||
p = l->first_op_buffer->ops;
|
||||
|
||||
while (1) {
|
||||
int op = p[0].op;
|
||||
if (op == OP_EndList)
|
||||
break;
|
||||
if (op == OP_NextBuffer) {
|
||||
p = (GLParam *)p[1].p;
|
||||
} else {
|
||||
op_table_func[op](this, p);
|
||||
p += op_table_size[op];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_NewList(TGLuint list, TGLenum mode) {
|
||||
assert(mode == TGL_COMPILE || mode == TGL_COMPILE_AND_EXECUTE);
|
||||
assert(compile_flag == 0);
|
||||
|
||||
GLList *l = find_list(list);
|
||||
if (l)
|
||||
delete_list(list);
|
||||
l = alloc_list(list);
|
||||
|
||||
current_op_buffer = l->first_op_buffer;
|
||||
current_op_buffer_index = 0;
|
||||
|
||||
compile_flag = 1;
|
||||
exec_flag = (mode == TGL_COMPILE_AND_EXECUTE);
|
||||
}
|
||||
|
||||
void GLContext::gl_EndList() {
|
||||
GLParam p[1];
|
||||
|
||||
assert(compile_flag == 1);
|
||||
|
||||
// end of list
|
||||
p[0].op = OP_EndList;
|
||||
gl_compile_op(p);
|
||||
|
||||
compile_flag = 0;
|
||||
exec_flag = 1;
|
||||
}
|
||||
|
||||
TGLboolean GLContext::gl_IsList(TGLuint list) {
|
||||
GLList *l = find_list(list);
|
||||
|
||||
return (l != nullptr);
|
||||
}
|
||||
|
||||
TGLuint GLContext::gl_GenLists(TGLsizei range) {
|
||||
GLList **lists = shared_state.lists;
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < MAX_DISPLAY_LISTS; i++) {
|
||||
if (!lists[i]) {
|
||||
count++;
|
||||
if (count == range) {
|
||||
uint list = i - range + 1;
|
||||
for (int j = 0; j < range; j++) {
|
||||
alloc_list(list + j);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
251
graphics/tinygl/matrix.cpp
Normal file
251
graphics/tinygl/matrix.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::gl_print_matrix(const float *m) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fprintf(stderr, "%f %f %f %f\n", m[i], m[4 + i], m[8 + i], m[12 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gl_matrix_update(GLContext *c) {
|
||||
c->matrix_model_projection_updated |= (c->matrix_mode <= 1);
|
||||
}
|
||||
|
||||
void GLContext::glopMatrixMode(GLParam *p) {
|
||||
int mode = p[1].i;
|
||||
switch (mode) {
|
||||
case TGL_MODELVIEW:
|
||||
matrix_mode = 0;
|
||||
break;
|
||||
case TGL_PROJECTION:
|
||||
matrix_mode = 1;
|
||||
break;
|
||||
case TGL_TEXTURE:
|
||||
matrix_mode = 2;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopLoadMatrix(GLParam *p) {
|
||||
Matrix4 *m;
|
||||
GLParam *q;
|
||||
|
||||
m = matrix_stack_ptr[matrix_mode];
|
||||
q = p + 1;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m->_m[0][i] = q[0].f;
|
||||
m->_m[1][i] = q[1].f;
|
||||
m->_m[2][i] = q[2].f;
|
||||
m->_m[3][i] = q[3].f;
|
||||
q += 4;
|
||||
}
|
||||
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopLoadIdentity(GLParam *) {
|
||||
matrix_stack_ptr[matrix_mode]->identity();
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopMultMatrix(GLParam *p) {
|
||||
Matrix4 m;
|
||||
GLParam *q;
|
||||
q = p + 1;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m._m[0][i] = q[0].f;
|
||||
m._m[1][i] = q[1].f;
|
||||
m._m[2][i] = q[2].f;
|
||||
m._m[3][i] = q[3].f;
|
||||
q += 4;
|
||||
}
|
||||
|
||||
*matrix_stack_ptr[matrix_mode] *= m;
|
||||
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopPushMatrix(GLParam *) {
|
||||
int n = matrix_mode;
|
||||
Matrix4 *m;
|
||||
|
||||
assert((matrix_stack_ptr[n] - matrix_stack[n] + 1) < matrix_stack_depth_max[n]);
|
||||
|
||||
m = ++matrix_stack_ptr[n];
|
||||
|
||||
m[0] = m[-1];
|
||||
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopPopMatrix(GLParam *) {
|
||||
int n = matrix_mode;
|
||||
|
||||
assert(matrix_stack_ptr[n] > matrix_stack[n]);
|
||||
matrix_stack_ptr[n]--;
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopRotate(GLParam *p) {
|
||||
Matrix4 m;
|
||||
float u[3];
|
||||
float angle;
|
||||
int dir_code;
|
||||
|
||||
angle = (float)(p[1].f * (float)M_PI / 180.0);
|
||||
u[0] = p[2].f;
|
||||
u[1] = p[3].f;
|
||||
u[2] = p[4].f;
|
||||
|
||||
// simple case detection
|
||||
dir_code = ((u[0] != 0) << 2) | ((u[1] != 0) << 1) | (u[2] != 0);
|
||||
|
||||
switch (dir_code) {
|
||||
case 0:
|
||||
m.identity();
|
||||
break;
|
||||
case 4:
|
||||
if (u[0] < 0)
|
||||
angle = -angle;
|
||||
m.rotation(angle, 0);
|
||||
break;
|
||||
case 2:
|
||||
if (u[1] < 0)
|
||||
angle = -angle;
|
||||
m.rotation(angle, 1);
|
||||
break;
|
||||
case 1:
|
||||
if (u[2] < 0)
|
||||
angle = -angle;
|
||||
m.rotation(angle, 2);
|
||||
break;
|
||||
default: {
|
||||
float cost, sint;
|
||||
|
||||
// normalize vector
|
||||
float len = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
|
||||
if (len == 0.0f)
|
||||
return;
|
||||
len = 1.0f / sqrt(len);
|
||||
u[0] *= len;
|
||||
u[1] *= len;
|
||||
u[2] *= len;
|
||||
|
||||
// store cos and sin values
|
||||
cost = cos(angle);
|
||||
sint = sin(angle);
|
||||
|
||||
// fill in the values
|
||||
m._m[3][0] = 0.0f;
|
||||
m._m[3][2] = 0.0f;
|
||||
m._m[0][3] = 0.0f;
|
||||
m._m[1][3] = 0.0f;
|
||||
m._m[2][3] = 0.0f;
|
||||
m._m[3][3] = 1.0f;
|
||||
|
||||
// do the math
|
||||
m._m[0][0] = u[0] * u[0] + cost * (1 - u[0] * u[0]);
|
||||
m._m[1][0] = u[0] * u[1] * (1 -cost) - u[2] * sint;
|
||||
m._m[2][0] = u[2] * u[0] * (1 -cost) + u[1] * sint;
|
||||
m._m[0][1] = u[0] * u[1] * (1 -cost) + u[2] * sint;
|
||||
m._m[1][1] = u[1] * u[1] + cost * (1 - u[1] * u[1]);
|
||||
m._m[2][1] = u[1] * u[2] * (1 - cost) - u[0] * sint;
|
||||
m._m[0][2] = u[2] * u[0] * (1 - cost) - u[1] * sint;
|
||||
m._m[1][2] = u[1] * u[2] * (1 - cost) + u[0] * sint;
|
||||
m._m[2][2] = u[2] * u[2] + cost * (1 - u[2] * u[2]);
|
||||
}
|
||||
}
|
||||
|
||||
*matrix_stack_ptr[matrix_mode] *= m;
|
||||
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopScale(GLParam *p) {
|
||||
matrix_stack_ptr[matrix_mode]->scale(p[1].f, p[2].f, p[3].f);
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopTranslate(GLParam *p) {
|
||||
matrix_stack_ptr[matrix_mode]->translate(p[1].f, p[2].f, p[3].f);
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopFrustum(GLParam *p) {
|
||||
float left = p[1].f;
|
||||
float right = p[2].f;
|
||||
float bottom = p[3].f;
|
||||
float top = p[4].f;
|
||||
float nearp = p[5].f;
|
||||
float farp = p[6].f;
|
||||
Matrix4 m = Matrix4::frustum(left, right, bottom, top, nearp, farp);
|
||||
|
||||
*matrix_stack_ptr[matrix_mode] *= m;
|
||||
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
void GLContext::glopOrtho(GLParam *p) {
|
||||
float *r;
|
||||
TinyGL::Matrix4 m;
|
||||
float left = p[1].f;
|
||||
float right = p[2].f;
|
||||
float bottom = p[3].f;
|
||||
float top = p[4].f;
|
||||
float zNear = p[5].f;
|
||||
float zFar = p[6].f;
|
||||
|
||||
float a = 2.0f / (right - left);
|
||||
float b = 2.0f / (top - bottom);
|
||||
float c = -2.0f / (zFar - zNear);
|
||||
|
||||
float tx = -(right + left) / (right - left);
|
||||
float ty = -(top + bottom) / (top - bottom);
|
||||
float tz = -(zFar + zNear) / (zFar - zNear);
|
||||
|
||||
r = &m._m[0][0];
|
||||
r[0] = a; r[1] = 0; r[2] = 0; r[3] = tx;
|
||||
r[4] = 0; r[5] = b; r[6] = 0; r[7] = ty;
|
||||
r[8] = 0; r[9] = 0; r[10] = c; r[11] = tz;
|
||||
r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
|
||||
|
||||
*matrix_stack_ptr[matrix_mode] *= m;
|
||||
gl_matrix_update(this);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
52
graphics/tinygl/memory.cpp
Normal file
52
graphics/tinygl/memory.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
// Memory allocator for TinyGL
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
// modify these functions so that they suit your needs
|
||||
|
||||
void gl_free(void *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *gl_malloc(int size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *gl_zalloc(int size) {
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
void *gl_realloc(void *p, int size) {
|
||||
return realloc(p, size);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
253
graphics/tinygl/misc.cpp
Normal file
253
graphics/tinygl/misc.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopViewport(GLParam *p) {
|
||||
int xsize, ysize, xmin, ymin, xsize_req, ysize_req;
|
||||
|
||||
xmin = p[1].i;
|
||||
ymin = p[2].i;
|
||||
xsize = p[3].i;
|
||||
ysize = p[4].i;
|
||||
|
||||
// we may need to resize the zbuffer
|
||||
|
||||
if (viewport.xmin != xmin || viewport.ymin != ymin ||
|
||||
viewport.xsize != xsize || viewport.ysize != ysize) {
|
||||
|
||||
xsize_req = xmin + xsize;
|
||||
ysize_req = ymin + ysize;
|
||||
|
||||
if (gl_resize_viewport && gl_resize_viewport(&xsize_req, &ysize_req) != 0) {
|
||||
error("glViewport: error while resizing display");
|
||||
}
|
||||
|
||||
xsize = xsize_req - xmin;
|
||||
ysize = ysize_req - ymin;
|
||||
if (xsize <= 0 || ysize <= 0) {
|
||||
error("glViewport: size too small");
|
||||
}
|
||||
|
||||
viewport.xmin = xmin;
|
||||
viewport.ymin = ymin;
|
||||
viewport.xsize = xsize;
|
||||
viewport.ysize = ysize;
|
||||
|
||||
viewport.updated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopScissor(GLParam *p) {
|
||||
scissor[0] = p[1].i;
|
||||
scissor[1] = p[2].i;
|
||||
scissor[2] = p[3].i;
|
||||
scissor[3] = p[4].i;
|
||||
}
|
||||
|
||||
void GLContext::glopEnableDisable(GLParam *p) {
|
||||
int code = p[1].i;
|
||||
int v = p[2].i;
|
||||
|
||||
switch (code) {
|
||||
case TGL_CULL_FACE:
|
||||
cull_face_enabled = v != 0;
|
||||
break;
|
||||
case TGL_LIGHTING:
|
||||
lighting_enabled = v != 0;
|
||||
break;
|
||||
case TGL_COLOR_MATERIAL:
|
||||
color_material_enabled = v != 0;
|
||||
break;
|
||||
case TGL_FOG:
|
||||
fog_enabled = v != 0;
|
||||
break;
|
||||
case TGL_TEXTURE_2D:
|
||||
texture_2d_enabled = v != 0;
|
||||
break;
|
||||
case TGL_NORMALIZE:
|
||||
normalize_enabled = v != 0;
|
||||
break;
|
||||
case TGL_DEPTH_TEST:
|
||||
depth_test_enabled = v != 0;
|
||||
break;
|
||||
case TGL_ALPHA_TEST:
|
||||
alpha_test_enabled = v != 0;
|
||||
break;
|
||||
case TGL_POLYGON_STIPPLE:
|
||||
polygon_stipple_enabled = v != 0;
|
||||
break;
|
||||
case TGL_STENCIL_TEST:
|
||||
stencil_test_enabled = v != 0;
|
||||
break;
|
||||
case TGL_SCISSOR_TEST:
|
||||
scissor_test_enabled = v != 0;
|
||||
break;
|
||||
case TGL_BLEND:
|
||||
blending_enabled = v != 0;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_FILL:
|
||||
if (v)
|
||||
offset_states |= TGL_OFFSET_FILL;
|
||||
else
|
||||
offset_states &= ~TGL_OFFSET_FILL;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_POINT:
|
||||
if (v)
|
||||
offset_states |= TGL_OFFSET_POINT;
|
||||
else
|
||||
offset_states &= ~TGL_OFFSET_POINT;
|
||||
break;
|
||||
case TGL_POLYGON_OFFSET_LINE:
|
||||
if (v)
|
||||
offset_states |= TGL_OFFSET_LINE;
|
||||
else
|
||||
offset_states &= ~TGL_OFFSET_LINE;
|
||||
break;
|
||||
case TGL_TWO_COLOR_STIPPLE:
|
||||
two_color_stipple_enabled = v != 0;
|
||||
break;
|
||||
default:
|
||||
if (code >= TGL_LIGHT0 && code < TGL_LIGHT0 + T_MAX_LIGHTS) {
|
||||
gl_enable_disable_light(code - TGL_LIGHT0, v);
|
||||
} else {
|
||||
//warning("glEnableDisable: 0x%X not supported.", code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopBlendFunc(GLParam *p) {
|
||||
source_blending_factor = p[1].i;
|
||||
destination_blending_factor = p[2].i;
|
||||
}
|
||||
|
||||
void GLContext::glopAlphaFunc(GLParam *p) {
|
||||
alpha_test_func = p[1].i;
|
||||
alpha_test_ref_val = (int)(p[2].f * 255);
|
||||
}
|
||||
|
||||
void GLContext::glopDepthFunc(GLParam *p) {
|
||||
depth_func = p[1].i;
|
||||
}
|
||||
|
||||
void GLContext::glopStencilFunc(GLParam *p) {
|
||||
TGLenum func = p[1].i;
|
||||
TGLint ref = p[2].i;
|
||||
TGLuint mask = p[3].ui;
|
||||
if (func < TGL_NEVER || func > TGL_ALWAYS)
|
||||
return;
|
||||
if (ref < 0)
|
||||
ref = 0;
|
||||
else if (ref > 255)
|
||||
ref = 255;
|
||||
stencil_test_func = func;
|
||||
stencil_ref_val = (byte)ref;
|
||||
stencil_mask = (byte)mask;
|
||||
}
|
||||
|
||||
void GLContext::glopStencilOp(GLParam *p) {
|
||||
stencil_sfail = p[1].i;
|
||||
stencil_dpfail = p[2].i;
|
||||
stencil_dppass = p[3].i;
|
||||
}
|
||||
|
||||
void GLContext::glopShadeModel(GLParam *p) {
|
||||
int code = p[1].i;
|
||||
current_shade_model = code;
|
||||
}
|
||||
|
||||
void GLContext::glopCullFace(GLParam *p) {
|
||||
int code = p[1].i;
|
||||
current_cull_face = code;
|
||||
}
|
||||
|
||||
void GLContext::glopFrontFace(GLParam *p) {
|
||||
int code = p[1].i;
|
||||
current_front_face = code;
|
||||
}
|
||||
|
||||
void GLContext::glopPolygonMode(GLParam *p) {
|
||||
int face = p[1].i;
|
||||
int mode = p[2].i;
|
||||
|
||||
switch (face) {
|
||||
case TGL_BACK:
|
||||
polygon_mode_back = mode;
|
||||
break;
|
||||
case TGL_FRONT:
|
||||
polygon_mode_front = mode;
|
||||
break;
|
||||
case TGL_FRONT_AND_BACK:
|
||||
polygon_mode_front = mode;
|
||||
polygon_mode_back = mode;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopHint(GLParam *) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void GLContext::glopPolygonStipple(GLParam *p) {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
polygon_stipple_pattern[i] = p[i + 1].ui;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopStippleColor(GLParam *p) {
|
||||
int r = (int)p[1].f;
|
||||
int g = (int)p[2].f;
|
||||
int b = (int)p[3].f;
|
||||
stippleColor = r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
void GLContext::glopPolygonOffset(GLParam *p) {
|
||||
offset_factor = p[1].f;
|
||||
offset_units = p[2].f;
|
||||
}
|
||||
|
||||
void GLContext::glopColorMask(GLParam *p) {
|
||||
color_mask_red = p[1].i == TGL_TRUE;
|
||||
color_mask_green = p[2].i == TGL_TRUE;
|
||||
color_mask_blue = p[3].i == TGL_TRUE;
|
||||
color_mask_alpha = p[4].i == TGL_TRUE;
|
||||
}
|
||||
|
||||
void GLContext::glopDepthMask(GLParam *p) {
|
||||
depth_write_mask = p[1].i == TGL_TRUE;
|
||||
}
|
||||
|
||||
void GLContext::glopStencilMask(TinyGL::GLParam *p) {
|
||||
stencil_write_mask = p[1].ui;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
108
graphics/tinygl/opinfo.h
Normal file
108
graphics/tinygl/opinfo.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
|
||||
ADD_OP(Color, 4, "%f %f %f %f")
|
||||
ADD_OP(TexCoord, 4, "%f %f %f %f")
|
||||
ADD_OP(EdgeFlag, 1, "%d")
|
||||
ADD_OP(Normal, 3, "%f %f %f")
|
||||
|
||||
ADD_OP(Begin, 1, "%C")
|
||||
ADD_OP(Vertex, 4, "%f %f %f %f")
|
||||
ADD_OP(End, 0, "")
|
||||
|
||||
ADD_OP(EnableDisable, 2, "%C %d")
|
||||
|
||||
ADD_OP(MatrixMode, 1, "%C")
|
||||
ADD_OP(LoadMatrix, 16, "")
|
||||
ADD_OP(LoadIdentity, 0, "")
|
||||
ADD_OP(MultMatrix, 16, "")
|
||||
ADD_OP(PushMatrix, 0, "")
|
||||
ADD_OP(PopMatrix, 0, "")
|
||||
ADD_OP(Rotate, 4, "%f %f %f %f")
|
||||
ADD_OP(Translate, 3, "%f %f %f")
|
||||
ADD_OP(Scale, 3, "%f %f %f")
|
||||
ADD_OP(Ortho, 6, "%f %f %f %f %f %f")
|
||||
|
||||
ADD_OP(Scissor, 4, "%d %d %d %d")
|
||||
ADD_OP(Viewport, 4, "%d %d %d %d")
|
||||
ADD_OP(Frustum, 6, "%f %f %f %f %f %f")
|
||||
|
||||
ADD_OP(Material, 6, "%C %C %f %f %f %f")
|
||||
ADD_OP(ColorMaterial, 2, "%C %C")
|
||||
ADD_OP(Light, 6, "%C %C %f %f %f %f")
|
||||
ADD_OP(LightModel, 5, "%C %f %f %f %f")
|
||||
|
||||
ADD_OP(Clear, 1, "%d")
|
||||
ADD_OP(ClearColor, 4, "%f %f %f %f")
|
||||
ADD_OP(ClearDepth, 1, "%f")
|
||||
ADD_OP(ClearStencil, 1, "%d")
|
||||
|
||||
ADD_OP(InitNames, 0, "")
|
||||
ADD_OP(PushName, 1, "%d")
|
||||
ADD_OP(PopName, 0, "")
|
||||
ADD_OP(LoadName, 1, "%d")
|
||||
|
||||
ADD_OP(TexImage2D, 9, "%d %d %d %d %d %d %d %d %d")
|
||||
ADD_OP(BindTexture, 2, "%C %d")
|
||||
ADD_OP(TexEnv, 7, "%C %C %C %f %f %f %f")
|
||||
ADD_OP(TexParameter, 7, "%C %C %C %f %f %f %f")
|
||||
|
||||
ADD_OP(ShadeModel, 1, "%C")
|
||||
ADD_OP(CullFace, 1, "%C")
|
||||
ADD_OP(FrontFace, 1, "%C")
|
||||
ADD_OP(PolygonMode, 2, "%C %C")
|
||||
ADD_OP(ColorMask, 1, "%08x")
|
||||
ADD_OP(DepthMask, 1, "%d")
|
||||
ADD_OP(StencilMask, 1, "%d")
|
||||
ADD_OP(BlendFunc, 2, "%d %d")
|
||||
ADD_OP(AlphaFunc, 2, "%d %f")
|
||||
ADD_OP(DepthFunc, 1, "%d")
|
||||
ADD_OP(StencilFunc, 3, "%C %d %d")
|
||||
ADD_OP(StencilOp, 3, "%C %C %C")
|
||||
|
||||
ADD_OP(PolygonStipple, 128, "%d")
|
||||
ADD_OP(StippleColor, 3, "%f %f %f")
|
||||
|
||||
ADD_OP(Fog, 5, "%d %f %f %f %f")
|
||||
|
||||
ADD_OP(CallList, 1, "%d")
|
||||
ADD_OP(Hint, 2, "%C %C")
|
||||
|
||||
// special opcodes
|
||||
ADD_OP(EndList, 0, "")
|
||||
ADD_OP(NextBuffer, 1, "%p")
|
||||
|
||||
// opengl 1.1 arrays
|
||||
ADD_OP(ArrayElement, 1, "%d")
|
||||
ADD_OP(DrawArrays, 3, "%C %d %d")
|
||||
ADD_OP(DrawElements, 4, "%C %d %C %p")
|
||||
|
||||
// opengl 1.1 polygon offset
|
||||
ADD_OP(PolygonOffset, 2, "%f %f")
|
||||
|
||||
#undef ADD_OP
|
||||
125
graphics/tinygl/pixelbuffer.cpp
Normal file
125
graphics/tinygl/pixelbuffer.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/pixelbuffer.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
PixelBuffer::PixelBuffer()
|
||||
: _buffer(nullptr),
|
||||
_dispose(DisposeAfterUse::NO) {
|
||||
|
||||
}
|
||||
|
||||
PixelBuffer::PixelBuffer(const PixelFormat &format, int buffersize, DisposeAfterUse::Flag dispose)
|
||||
: _buffer(nullptr),
|
||||
_dispose(DisposeAfterUse::NO) {
|
||||
create(format, buffersize, dispose);
|
||||
}
|
||||
|
||||
PixelBuffer::PixelBuffer(const PixelFormat &format, byte *buffer)
|
||||
: _buffer(buffer),
|
||||
_format(format),
|
||||
_dispose(DisposeAfterUse::NO) {
|
||||
|
||||
}
|
||||
|
||||
PixelBuffer::PixelBuffer(const PixelBuffer &buf) {
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
PixelBuffer::~PixelBuffer() {
|
||||
if (_dispose == DisposeAfterUse::YES)
|
||||
free();
|
||||
}
|
||||
|
||||
void PixelBuffer::create(const Graphics::PixelFormat &format, int buffersize, DisposeAfterUse::Flag dispose) {
|
||||
if (_dispose == DisposeAfterUse::YES)
|
||||
free();
|
||||
|
||||
_format = format;
|
||||
_dispose = dispose;
|
||||
_buffer = new byte[buffersize * format.bytesPerPixel];
|
||||
}
|
||||
|
||||
void PixelBuffer::create(int buffersize, DisposeAfterUse::Flag dispose) {
|
||||
if (_dispose == DisposeAfterUse::YES)
|
||||
free();
|
||||
|
||||
_dispose = dispose;
|
||||
_buffer = new byte[buffersize * _format.bytesPerPixel];
|
||||
}
|
||||
|
||||
void PixelBuffer::set(const Graphics::PixelFormat &format, byte *buffer) {
|
||||
if (_dispose == DisposeAfterUse::YES)
|
||||
free();
|
||||
|
||||
_format = format;
|
||||
_buffer = buffer;
|
||||
}
|
||||
|
||||
void PixelBuffer::free() {
|
||||
delete[] _buffer;
|
||||
_buffer = nullptr;
|
||||
}
|
||||
|
||||
void PixelBuffer::clear(uint length) {
|
||||
memset(_buffer, 0, length * _format.bytesPerPixel);
|
||||
}
|
||||
|
||||
void PixelBuffer::copyBuffer(int thisFrom, int otherFrom, int length, const PixelBuffer &buf) {
|
||||
if (buf._format.bytesPerPixel == _format.bytesPerPixel &&
|
||||
buf._format.rShift == _format.rShift &&
|
||||
buf._format.gShift == _format.gShift &&
|
||||
buf._format.bShift == _format.bShift &&
|
||||
buf._format.rLoss == _format.rLoss &&
|
||||
buf._format.gLoss == _format.gLoss &&
|
||||
buf._format.bLoss == _format.bLoss && (
|
||||
_format.aLoss == 8 ||
|
||||
buf._format.aLoss == _format.aLoss
|
||||
)
|
||||
) {
|
||||
memcpy(_buffer + thisFrom * _format.bytesPerPixel, buf._buffer + otherFrom * _format.bytesPerPixel, length * _format.bytesPerPixel);
|
||||
} else {
|
||||
uint8 r, g, b, a;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
buf.getARGBAt(i + otherFrom, a, r, g, b);
|
||||
setPixelAt(i + thisFrom, a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PixelBuffer &PixelBuffer::operator=(const PixelBuffer &buf) {
|
||||
_buffer = buf._buffer;
|
||||
_format = buf._format;
|
||||
_dispose = DisposeAfterUse::NO;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PixelBuffer &PixelBuffer::operator=(byte *buffer) {
|
||||
_buffer = buffer;
|
||||
_dispose = DisposeAfterUse::NO;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
262
graphics/tinygl/pixelbuffer.h
Normal file
262
graphics/tinygl/pixelbuffer.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_PIXELBUFFER_H
|
||||
#define GRAPHICS_PIXELBUFFER_H
|
||||
|
||||
#include "common/types.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
/**
|
||||
* @defgroup graphics_pixelbuffer Pixel buffers
|
||||
* @ingroup graphics
|
||||
*
|
||||
* @brief Class for managing pixel buffers.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
class PixelBuffer {
|
||||
public:
|
||||
/**
|
||||
* Construct an empty PixelBuffer.
|
||||
*/
|
||||
PixelBuffer();
|
||||
/**
|
||||
* Construct a PixelBuffer, allocating the internal buffer.
|
||||
*
|
||||
* @param format The format of the pixels in this buffer.
|
||||
* @param buffersize The number of pixels the buffer will store.
|
||||
* @param dispose If YES the internal buffer will be deleted when this object is destroyed,
|
||||
*/
|
||||
PixelBuffer(const Graphics::PixelFormat &format, int buffersize, DisposeAfterUse::Flag dispose);
|
||||
/**
|
||||
* Construct a PixelBuffer, using an already allocated buffer.
|
||||
*
|
||||
* @param format The format of the pixels in this buffer.
|
||||
* @param buffer The raw buffer containing the pixels.
|
||||
*/
|
||||
PixelBuffer(const Graphics::PixelFormat &format, byte *buffer);
|
||||
/**
|
||||
* Copy constructor.
|
||||
* The internal buffer will NOT be duplicated, it will be shared between the instances.
|
||||
*/
|
||||
PixelBuffer(const PixelBuffer &buf);
|
||||
/**
|
||||
* Destroy the object.
|
||||
*/
|
||||
~PixelBuffer();
|
||||
|
||||
/**
|
||||
* Initialize the buffer.
|
||||
*
|
||||
* @param format The format of the pixels.
|
||||
* @param buffersize The number of pixels the buffer will store.
|
||||
* @param dispose If YES the internal buffer will be deleted when this object is destroyed,
|
||||
*/
|
||||
void create(const Graphics::PixelFormat &format, int buffersize, DisposeAfterUse::Flag dispose);
|
||||
/**
|
||||
* Initialize the buffer, using the already set pixel format.
|
||||
* @note If the pixel format was not set before the results are undefined.
|
||||
*
|
||||
* @param buffersize The number of pixels the buffer will store.
|
||||
* @param dispose If YES the internal buffer will be deleted when this object is destroyed,
|
||||
*/
|
||||
void create(int buffersize, DisposeAfterUse::Flag dispose);
|
||||
|
||||
/**
|
||||
* Initialize the buffer.
|
||||
*
|
||||
* @param format The format of the pixels in this buffer.
|
||||
* @param buffer The raw buffer containing the pixels.
|
||||
*/
|
||||
void set(const Graphics::PixelFormat &format, byte *buffer);
|
||||
|
||||
/**
|
||||
* Delete the internal pixel buffer.
|
||||
*/
|
||||
void free();
|
||||
|
||||
/**
|
||||
* Reset the value of the pixels.
|
||||
*
|
||||
* @param length The length of the buffer, in pixels.
|
||||
*/
|
||||
void clear(uint length);
|
||||
|
||||
/**
|
||||
* Set the value of the pixel at index 'pixel' to 'value',
|
||||
*/
|
||||
inline void setPixelAt(int pixel, uint32 value) {
|
||||
switch (_format.bytesPerPixel) {
|
||||
case 2:
|
||||
((uint16 *) _buffer)[pixel] = value;
|
||||
return;
|
||||
case 3:
|
||||
pixel *= 3;
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
_buffer[pixel + 0] = (value >> 16) & 0xFF;
|
||||
_buffer[pixel + 1] = (value >> 8) & 0xFF;
|
||||
_buffer[pixel + 2] = value & 0xFF;
|
||||
#elif defined(SCUMM_LITTLE_ENDIAN)
|
||||
_buffer[pixel + 0] = value & 0xFF;
|
||||
_buffer[pixel + 1] = (value >> 8) & 0xFF;
|
||||
_buffer[pixel + 2] = (value >> 16) & 0xFF;
|
||||
#endif
|
||||
return;
|
||||
case 4:
|
||||
((uint32 *) _buffer)[pixel] = value;
|
||||
return;
|
||||
}
|
||||
error("setPixelAt: Unhandled bytesPerPixel %d", int(_format.bytesPerPixel));
|
||||
}
|
||||
/**
|
||||
* Set the value of a pixel. The pixel will be converted from a pixel in another PixelBuffer,
|
||||
* at the same index.
|
||||
*
|
||||
* @param pixel The index of the pixel to set.
|
||||
* @param buf The buffer storing the source pixel.
|
||||
*/
|
||||
inline void setPixelAt(int pixel, const PixelBuffer &buf) { setPixelAt(pixel, buf, pixel); }
|
||||
/**
|
||||
* Set the value of a pixel. The pixel will be converted from a pixel in another PixelBuffer.
|
||||
*
|
||||
* @param thisPix The index of the pixel to set.
|
||||
* @param buf The buffer storing the source pixel.
|
||||
* @param otherPix The index of the source pixel in 'buf'.
|
||||
*/
|
||||
inline void setPixelAt(int thisPix, const PixelBuffer &buf, int otherPix) {
|
||||
if (_format == buf._format) {
|
||||
memcpy(getRawBuffer(thisPix), buf.getRawBuffer(otherPix), _format.bytesPerPixel);
|
||||
return;
|
||||
}
|
||||
uint8 a, r, g, b;
|
||||
buf.getARGBAt(otherPix, a, r, g, b);
|
||||
setPixelAt(thisPix, a, r, g, b);
|
||||
}
|
||||
/**
|
||||
* Set a pixel, from RGB values.
|
||||
*/
|
||||
inline void setPixelAt(int pixel, uint8 r, uint8 g, uint8 b) { setPixelAt(pixel, _format.RGBToColor(r, g, b)); }
|
||||
/**
|
||||
* Set a pixel, from ARGB values.
|
||||
*/
|
||||
inline void setPixelAt(int pixel, uint8 a, uint8 r, uint8 g, uint8 b) { setPixelAt(pixel, _format.ARGBToColor(a, r, g, b)); }
|
||||
|
||||
/**
|
||||
* Copy some pixels from a buffer. The pixels will be converted, storing the same ARGB value.
|
||||
*
|
||||
* @param from The starting index.
|
||||
* @param length The number of pixels to copy.
|
||||
* @param buf The source buffer.
|
||||
*/
|
||||
inline void copyBuffer(int from, int length, const PixelBuffer &buf) { copyBuffer(from, from, length, buf); }
|
||||
/**
|
||||
* Copy some pixels from a buffer. The pixels will be converted, storing the same ARGB value.
|
||||
*
|
||||
* @param thisFrom The starting index.
|
||||
* @param otherFrom The starting index in the source buffer.
|
||||
* @param length The number of pixels to copy.
|
||||
* @param buf The source buffer.
|
||||
*/
|
||||
void copyBuffer(int thisFrom, int otherFrom, int length, const PixelBuffer &buf);
|
||||
|
||||
/**
|
||||
* Shift the internal buffer of some pixels, losing some pixels at the start of the buffer.
|
||||
* The pixels lost will NOT be deleted.
|
||||
*/
|
||||
inline void shiftBy(int amount) { _buffer += amount * _format.bytesPerPixel; }
|
||||
|
||||
/**
|
||||
* Return the encoded value of the pixel at the given index.
|
||||
*/
|
||||
inline uint32 getValueAt(int i) const {
|
||||
switch (_format.bytesPerPixel) {
|
||||
case 2:
|
||||
return ((uint16 *) _buffer)[i];
|
||||
case 3:
|
||||
i *= 3;
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
return (_buffer[i + 0] << 16) | (_buffer[i + 1] << 8) | _buffer[i + 2];
|
||||
#elif defined(SCUMM_LITTLE_ENDIAN)
|
||||
return _buffer[i + 0] | (_buffer[i + 1] << 8) | (_buffer[i + 2] << 16);
|
||||
#endif
|
||||
case 4:
|
||||
return ((uint32 *) _buffer)[i];
|
||||
}
|
||||
error("getValueAt: Unhandled bytesPerPixel %d", int(_format.bytesPerPixel));
|
||||
}
|
||||
/**
|
||||
* Return the RGB value of the pixel at the given index.
|
||||
*/
|
||||
inline void getRGBAt(int i, uint8 &r, uint8 &g, uint8 &b) const { _format.colorToRGB(getValueAt(i), r, g, b); }
|
||||
/**
|
||||
* Return the ARGB value of the pixel at the given index.
|
||||
*/
|
||||
inline void getARGBAt(int i, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const { _format.colorToARGB(getValueAt(i), a, r, g, b); }
|
||||
|
||||
/**
|
||||
* Return the internal buffer.
|
||||
*/
|
||||
inline byte *getRawBuffer() const { return _buffer; }
|
||||
/**
|
||||
* Return the internal buffer, pointing at the wanted pixel.
|
||||
*/
|
||||
inline byte *getRawBuffer(int pixel) const { return _buffer + _format.bytesPerPixel * pixel; }
|
||||
|
||||
/**
|
||||
* Return the pixel format used.
|
||||
*/
|
||||
inline const PixelFormat &getFormat() const { return _format; }
|
||||
|
||||
/**
|
||||
* Copy a PixelBuffer object.
|
||||
* The internal buffer will NOT be duplicated, it will be shared between the instances.
|
||||
*/
|
||||
PixelBuffer &operator=(const PixelBuffer &buf);
|
||||
/**
|
||||
* Set the internal buffer to an already allocated array.
|
||||
*
|
||||
* @param buffer The pointer to the array.
|
||||
*/
|
||||
PixelBuffer &operator=(byte *buffer);
|
||||
|
||||
/**
|
||||
* Check if the interal buffer is allocated.
|
||||
*
|
||||
* @returns true if allocated.
|
||||
*/
|
||||
inline operator bool() const { return (_buffer); }
|
||||
|
||||
private:
|
||||
byte *_buffer;
|
||||
Graphics::PixelFormat _format;
|
||||
DisposeAfterUse::Flag _dispose;
|
||||
};
|
||||
|
||||
}
|
||||
/** @} */
|
||||
#endif
|
||||
136
graphics/tinygl/select.cpp
Normal file
136
graphics/tinygl/select.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
TGLint GLContext::gl_RenderMode(TGLenum mode) {
|
||||
int result = 0;
|
||||
|
||||
switch (render_mode) {
|
||||
case TGL_RENDER:
|
||||
break;
|
||||
case TGL_SELECT:
|
||||
if (select_overflow) {
|
||||
result = -select_hits;
|
||||
} else {
|
||||
result = select_hits;
|
||||
}
|
||||
select_overflow = 0;
|
||||
select_ptr = select_buffer;
|
||||
name_stack_size = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
switch (mode) {
|
||||
case TGL_RENDER:
|
||||
render_mode = TGL_RENDER;
|
||||
break;
|
||||
case TGL_SELECT:
|
||||
render_mode = TGL_SELECT;
|
||||
assert(select_buffer != nullptr);
|
||||
select_ptr = select_buffer;
|
||||
select_hits = 0;
|
||||
select_overflow = 0;
|
||||
select_hit = nullptr;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void GLContext::gl_SelectBuffer(TGLsizei size, TGLuint *buffer) {
|
||||
assert(render_mode != TGL_SELECT);
|
||||
|
||||
select_buffer = buffer;
|
||||
select_size = size;
|
||||
}
|
||||
|
||||
void GLContext::glopInitNames(GLParam *) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
name_stack_size = 0;
|
||||
select_hit = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopPushName(GLParam *p) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
assert(name_stack_size < MAX_NAME_STACK_DEPTH);
|
||||
name_stack[name_stack_size++] = p[1].i;
|
||||
select_hit = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopPopName(GLParam *) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
assert(name_stack_size > 0);
|
||||
name_stack_size--;
|
||||
select_hit = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::glopLoadName(GLParam *p) {
|
||||
if (render_mode == TGL_SELECT) {
|
||||
assert(name_stack_size > 0);
|
||||
name_stack[name_stack_size - 1] = p[1].i;
|
||||
select_hit = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_add_select(uint zmin, uint zmax) {
|
||||
uint *ptr;
|
||||
int n;
|
||||
|
||||
if (!select_overflow) {
|
||||
if (!select_hit) {
|
||||
n = name_stack_size;
|
||||
if ((select_ptr - select_buffer + 3 + n) > select_size) {
|
||||
select_overflow = 1;
|
||||
} else {
|
||||
ptr = select_ptr;
|
||||
select_hit = ptr;
|
||||
*ptr++ = name_stack_size;
|
||||
*ptr++ = zmin;
|
||||
*ptr++ = zmax;
|
||||
for (int i = 0; i < n; i++)
|
||||
*ptr++ = name_stack[i];
|
||||
select_ptr = ptr;
|
||||
select_hits++;
|
||||
}
|
||||
} else {
|
||||
if (zmin < select_hit[1])
|
||||
select_hit[1] = zmin;
|
||||
if (zmax > select_hit[2])
|
||||
select_hit[2] = zmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
85
graphics/tinygl/specbuf.cpp
Normal file
85
graphics/tinygl/specbuf.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
static void calc_buf(GLSpecBuf *buf, const float shininess) {
|
||||
float val, inc;
|
||||
val = 0.0f;
|
||||
inc = 1.0f / SPECULAR_BUFFER_SIZE;
|
||||
for (int i = 0; i <= SPECULAR_BUFFER_SIZE; i++) {
|
||||
buf->buf[i] = pow(val, shininess);
|
||||
val += inc;
|
||||
}
|
||||
}
|
||||
|
||||
GLSpecBuf *GLContext::specbuf_get_buffer(const int shininess_i, const float shininess) {
|
||||
GLSpecBuf *found, *oldest;
|
||||
found = oldest = specbuf_first;
|
||||
while (found && found->shininess_i != shininess_i) {
|
||||
if (found->last_used < oldest->last_used) {
|
||||
oldest = found;
|
||||
}
|
||||
found = found->next;
|
||||
}
|
||||
if (found) {
|
||||
found->last_used = specbuf_used_counter++;
|
||||
return found;
|
||||
}
|
||||
if (!oldest || specbuf_num_buffers < MAX_SPECULAR_BUFFERS) {
|
||||
// create new buffer
|
||||
GLSpecBuf *buf = (GLSpecBuf *)gl_malloc(sizeof(GLSpecBuf));
|
||||
if (!buf)
|
||||
error("could not allocate specular buffer");
|
||||
specbuf_num_buffers++;
|
||||
buf->next = specbuf_first;
|
||||
specbuf_first = buf;
|
||||
buf->last_used = specbuf_used_counter++;
|
||||
buf->shininess_i = shininess_i;
|
||||
calc_buf(buf, shininess);
|
||||
return buf;
|
||||
}
|
||||
//overwrite the lru buffer
|
||||
oldest->shininess_i = shininess_i;
|
||||
oldest->last_used = specbuf_used_counter++;
|
||||
calc_buf(oldest, shininess);
|
||||
return oldest;
|
||||
}
|
||||
|
||||
void GLContext::specbuf_cleanup() {
|
||||
GLSpecBuf *buf, *next;
|
||||
buf = specbuf_first;
|
||||
for (int i = 0; i < specbuf_num_buffers; ++i) {
|
||||
next = buf->next;
|
||||
gl_free(buf);
|
||||
buf = next;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
339
graphics/tinygl/texelbuffer.cpp
Normal file
339
graphics/tinygl/texelbuffer.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/gl.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/zbuffer.h"
|
||||
#include "graphics/tinygl/colormasks.h"
|
||||
#include "graphics/tinygl/pixelbuffer.h"
|
||||
#include "graphics/tinygl/texelbuffer.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
#define ZB_POINT_ST_UNIT (1 << ZB_POINT_ST_FRAC_BITS)
|
||||
#define ZB_POINT_ST_FRAC_MASK (ZB_POINT_ST_UNIT - 1)
|
||||
|
||||
TexelBuffer::TexelBuffer(uint width, uint height, uint textureSize, int internalformat) {
|
||||
assert(width);
|
||||
assert(height);
|
||||
assert(textureSize);
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_fracTextureUnit = textureSize << ZB_POINT_ST_FRAC_BITS;
|
||||
_fracTextureMask = _fracTextureUnit - 1;
|
||||
_widthRatio = (float) width / textureSize;
|
||||
_heightRatio = (float) height / textureSize;
|
||||
_internalformat = internalformat;
|
||||
}
|
||||
|
||||
static inline uint wrap(uint wrap_mode, int coord, uint _fracTextureUnit, uint _fracTextureMask) {
|
||||
switch (wrap_mode) {
|
||||
case TGL_MIRRORED_REPEAT:
|
||||
if (coord & _fracTextureUnit)
|
||||
return _fracTextureMask - (coord & _fracTextureMask);
|
||||
return coord & _fracTextureMask;
|
||||
case TGL_CLAMP_TO_EDGE:
|
||||
if (coord < 0)
|
||||
return 0;
|
||||
if ((uint) coord > _fracTextureMask)
|
||||
return _fracTextureMask;
|
||||
return coord;
|
||||
default:
|
||||
// Fall through
|
||||
case TGL_REPEAT:
|
||||
return coord & _fracTextureMask;
|
||||
}
|
||||
}
|
||||
|
||||
void TexelBuffer::getARGBAt(
|
||||
uint wrap_s, uint wrap_t,
|
||||
int s, int t,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const {
|
||||
uint x, y;
|
||||
x = wrap(wrap_s, s, _fracTextureUnit, _fracTextureMask) * _widthRatio;
|
||||
y = wrap(wrap_t, t, _fracTextureUnit, _fracTextureMask) * _heightRatio;
|
||||
getARGBAt(
|
||||
(x >> ZB_POINT_ST_FRAC_BITS) + (y >> ZB_POINT_ST_FRAC_BITS) * _width,
|
||||
x & ZB_POINT_ST_FRAC_MASK, y & ZB_POINT_ST_FRAC_MASK,
|
||||
a, r, g, b
|
||||
);
|
||||
}
|
||||
|
||||
// Nearest: store texture in original size.
|
||||
class BaseNearestTexelBuffer : public TexelBuffer {
|
||||
public:
|
||||
BaseNearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat);
|
||||
~BaseNearestTexelBuffer();
|
||||
|
||||
protected:
|
||||
byte *_buf;
|
||||
Graphics::PixelFormat _format;
|
||||
};
|
||||
|
||||
BaseNearestTexelBuffer::BaseNearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat)
|
||||
: TexelBuffer(width, height, textureSize, internalformat), _format(format) {
|
||||
uint count = _width * _height * _format.bytesPerPixel;
|
||||
_buf = (byte *)gl_malloc(count);
|
||||
memcpy(_buf, buf, count);
|
||||
}
|
||||
|
||||
BaseNearestTexelBuffer::~BaseNearestTexelBuffer() {
|
||||
gl_free(_buf);
|
||||
}
|
||||
|
||||
template<uint Format, uint Type>
|
||||
class NearestTexelBuffer final : public BaseNearestTexelBuffer {
|
||||
public:
|
||||
NearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat)
|
||||
: BaseNearestTexelBuffer(buf, format, width, height, textureSize, internalformat) {}
|
||||
|
||||
protected:
|
||||
void getARGBAt(
|
||||
uint pixel,
|
||||
uint, uint,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const override {
|
||||
Pixel col = *(((const Pixel *)_buf) + pixel);
|
||||
_format.colorToARGBT<ColorMask>(col, a, r, g, b);
|
||||
}
|
||||
|
||||
typedef ColorMasks<Format, Type> ColorMask;
|
||||
typedef typename ColorMask::PixelType Pixel;
|
||||
};
|
||||
|
||||
template<>
|
||||
class NearestTexelBuffer<TGL_RGB, TGL_UNSIGNED_BYTE> final : public BaseNearestTexelBuffer {
|
||||
public:
|
||||
NearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat)
|
||||
: BaseNearestTexelBuffer(buf, format, width, height, textureSize, internalformat) {}
|
||||
|
||||
protected:
|
||||
void getARGBAt(
|
||||
uint pixel,
|
||||
uint, uint,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const override {
|
||||
byte *col = _buf + (pixel * 3);
|
||||
a = 0xff;
|
||||
r = col[0];
|
||||
g = col[1];
|
||||
b = col[2];
|
||||
}
|
||||
};
|
||||
|
||||
TexelBuffer *createNearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &pf, uint format, uint type, uint width, uint height, uint textureSize, int internalformat) {
|
||||
if (format == TGL_RGBA && type == TGL_UNSIGNED_BYTE) {
|
||||
return new NearestTexelBuffer<TGL_RGBA, TGL_UNSIGNED_BYTE>(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
} else if (format == TGL_RGB && type == TGL_UNSIGNED_BYTE) {
|
||||
return new NearestTexelBuffer<TGL_RGB, TGL_UNSIGNED_BYTE>(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
} else if (format == TGL_RGB && type == TGL_UNSIGNED_SHORT_5_6_5) {
|
||||
return new NearestTexelBuffer<TGL_RGB, TGL_UNSIGNED_SHORT_5_6_5>(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
} else if (format == TGL_RGBA && type == TGL_UNSIGNED_SHORT_5_5_5_1) {
|
||||
return new NearestTexelBuffer<TGL_RGBA, TGL_UNSIGNED_SHORT_5_5_5_1>(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
} else if (format == TGL_RGBA && type == TGL_UNSIGNED_SHORT_4_4_4_4) {
|
||||
return new NearestTexelBuffer<TGL_RGBA, TGL_UNSIGNED_SHORT_4_4_4_4>(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
} else {
|
||||
error("TinyGL texture: format 0x%04x and type 0x%04x combination not supported", format, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Bilinear: each texture coordinates corresponds to the 4 original image
|
||||
// pixels linear interpolation has to work on, so that they are near each
|
||||
// other in CPU data cache, and a single actual memory fetch happens. This
|
||||
// allows applying linear filtering at render time at a very low performance
|
||||
// cost. As we expect to work on small-ish textures (512*512 ?) the 4x memory
|
||||
// usage increase should be negligible.
|
||||
class BilinearTexelBuffer : public TexelBuffer {
|
||||
public:
|
||||
BilinearTexelBuffer(byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat);
|
||||
~BilinearTexelBuffer();
|
||||
|
||||
protected:
|
||||
void getARGBAt(
|
||||
uint pixel,
|
||||
uint ds, uint dt,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const override;
|
||||
|
||||
private:
|
||||
uint32 *_texels;
|
||||
};
|
||||
|
||||
#define A_OFFSET (0 * 4)
|
||||
#define R_OFFSET (1 * 4)
|
||||
#define G_OFFSET (2 * 4)
|
||||
#define B_OFFSET (3 * 4)
|
||||
#define P00_OFFSET 0
|
||||
#define P01_OFFSET 1
|
||||
#define P10_OFFSET 2
|
||||
#define P11_OFFSET 3
|
||||
#define PIXEL_PER_TEXEL_SHIFT 2
|
||||
|
||||
BilinearTexelBuffer::BilinearTexelBuffer(byte *buf, const Graphics::PixelFormat &format, uint width, uint height, uint textureSize, int internalformat)
|
||||
: TexelBuffer(width, height, textureSize, internalformat) {
|
||||
const Graphics::PixelBuffer src(format, buf);
|
||||
|
||||
uint pixel00_offset = 0, pixel11_offset, pixel01_offset, pixel10_offset;
|
||||
uint8 *texel8;
|
||||
uint32 *texel32;
|
||||
|
||||
texel32 = _texels = (uint32 *)gl_malloc((_width * _height << PIXEL_PER_TEXEL_SHIFT) * sizeof(uint32));
|
||||
for (uint y = 0; y < _height; y++) {
|
||||
for (uint x = 0; x < _width; x++) {
|
||||
texel8 = (uint8 *)texel32;
|
||||
pixel11_offset = pixel00_offset + _width + 1;
|
||||
src.getARGBAt(
|
||||
pixel00_offset,
|
||||
*(texel8 + P00_OFFSET + A_OFFSET),
|
||||
*(texel8 + P00_OFFSET + R_OFFSET),
|
||||
*(texel8 + P00_OFFSET + G_OFFSET),
|
||||
*(texel8 + P00_OFFSET + B_OFFSET)
|
||||
);
|
||||
if ((x + 1) == _width) {
|
||||
pixel11_offset -= 1;
|
||||
pixel01_offset = pixel00_offset;
|
||||
} else
|
||||
pixel01_offset = pixel00_offset + 1;
|
||||
src.getARGBAt(
|
||||
pixel01_offset,
|
||||
*(texel8 + P01_OFFSET + A_OFFSET),
|
||||
*(texel8 + P01_OFFSET + R_OFFSET),
|
||||
*(texel8 + P01_OFFSET + G_OFFSET),
|
||||
*(texel8 + P01_OFFSET + B_OFFSET)
|
||||
);
|
||||
if ((y + 1) == _height) {
|
||||
pixel11_offset -= _width;
|
||||
pixel10_offset = pixel00_offset;
|
||||
} else
|
||||
pixel10_offset = pixel00_offset + _width;
|
||||
src.getARGBAt(
|
||||
pixel10_offset,
|
||||
*(texel8 + P10_OFFSET + A_OFFSET),
|
||||
*(texel8 + P10_OFFSET + R_OFFSET),
|
||||
*(texel8 + P10_OFFSET + G_OFFSET),
|
||||
*(texel8 + P10_OFFSET + B_OFFSET)
|
||||
);
|
||||
src.getARGBAt(
|
||||
pixel11_offset,
|
||||
*(texel8 + P11_OFFSET + A_OFFSET),
|
||||
*(texel8 + P11_OFFSET + R_OFFSET),
|
||||
*(texel8 + P11_OFFSET + G_OFFSET),
|
||||
*(texel8 + P11_OFFSET + B_OFFSET)
|
||||
);
|
||||
texel32 += 1 << PIXEL_PER_TEXEL_SHIFT;
|
||||
pixel00_offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BilinearTexelBuffer::~BilinearTexelBuffer() {
|
||||
gl_free(_texels);
|
||||
}
|
||||
|
||||
static inline int interpolate(int v00, int v01, int v10, int xf, int yf) {
|
||||
return v00 + (((v01 - v00) * xf + (v10 - v00) * yf) >> ZB_POINT_ST_FRAC_BITS);
|
||||
}
|
||||
|
||||
void BilinearTexelBuffer::getARGBAt(
|
||||
uint pixel,
|
||||
uint ds, uint dt,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const {
|
||||
uint p00_offset, p01_offset, p10_offset;
|
||||
uint8 *texel = (uint8 *)(_texels + (pixel << PIXEL_PER_TEXEL_SHIFT));
|
||||
if ((ds + dt) > ZB_POINT_ST_UNIT) {
|
||||
p00_offset = P11_OFFSET;
|
||||
p10_offset = P01_OFFSET;
|
||||
p01_offset = P10_OFFSET;
|
||||
ds = ZB_POINT_ST_UNIT - ds;
|
||||
dt = ZB_POINT_ST_UNIT - dt;
|
||||
} else {
|
||||
p00_offset = P00_OFFSET;
|
||||
p10_offset = P10_OFFSET;
|
||||
p01_offset = P01_OFFSET;
|
||||
}
|
||||
a = interpolate(
|
||||
*(texel + p00_offset + A_OFFSET),
|
||||
*(texel + p01_offset + A_OFFSET),
|
||||
*(texel + p10_offset + A_OFFSET),
|
||||
ds,
|
||||
dt
|
||||
);
|
||||
r = interpolate(
|
||||
*(texel + p00_offset + R_OFFSET),
|
||||
*(texel + p01_offset + R_OFFSET),
|
||||
*(texel + p10_offset + R_OFFSET),
|
||||
ds,
|
||||
dt
|
||||
);
|
||||
g = interpolate(
|
||||
*(texel + p00_offset + G_OFFSET),
|
||||
*(texel + p01_offset + G_OFFSET),
|
||||
*(texel + p10_offset + G_OFFSET),
|
||||
ds,
|
||||
dt
|
||||
);
|
||||
b = interpolate(
|
||||
*(texel + p00_offset + B_OFFSET),
|
||||
*(texel + p01_offset + B_OFFSET),
|
||||
*(texel + p10_offset + B_OFFSET),
|
||||
ds,
|
||||
dt
|
||||
);
|
||||
}
|
||||
|
||||
TexelBuffer *createBilinearTexelBuffer(byte *buf, const Graphics::PixelFormat &pf, uint format, uint type, uint width, uint height, uint textureSize, int internalformat) {
|
||||
return new BilinearTexelBuffer(
|
||||
buf, pf,
|
||||
width, height,
|
||||
textureSize,
|
||||
internalformat
|
||||
);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
58
graphics/tinygl/texelbuffer.h
Normal file
58
graphics/tinygl/texelbuffer.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TEXELBUFFER_H
|
||||
#define GRAPHICS_TEXELBUFFER_H
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
class TexelBuffer {
|
||||
public:
|
||||
TexelBuffer(uint width, uint height, uint textureSize, int internalformat);
|
||||
virtual ~TexelBuffer() {};
|
||||
|
||||
inline int internalformat() const { return _internalformat; }
|
||||
|
||||
void getARGBAt(
|
||||
uint wrap_s, uint wrap_t,
|
||||
int s, int t,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const;
|
||||
|
||||
protected:
|
||||
virtual void getARGBAt(
|
||||
uint pixel,
|
||||
uint ds, uint dt,
|
||||
uint8 &a, uint8 &r, uint8 &g, uint8 &b
|
||||
) const = 0;
|
||||
uint _width, _height, _fracTextureUnit, _fracTextureMask;
|
||||
float _widthRatio, _heightRatio;
|
||||
int _internalformat;
|
||||
};
|
||||
|
||||
TexelBuffer *createNearestTexelBuffer(const byte *buf, const Graphics::PixelFormat &pf, uint format, uint type, uint width, uint height, uint textureSize, int internalformat);
|
||||
TexelBuffer *createBilinearTexelBuffer(byte *buf, const Graphics::PixelFormat &pf, uint format, uint type, uint width, uint height, uint textureSize, int internalformat);
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
357
graphics/tinygl/texture.cpp
Normal file
357
graphics/tinygl/texture.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
// Texture Manager
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
GLTexture *GLContext::find_texture(uint h) {
|
||||
GLTexture *t;
|
||||
|
||||
t = shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
|
||||
while (t) {
|
||||
if (t->handle == h)
|
||||
return t;
|
||||
t = t->next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GLContext::free_texture(GLTexture *t) {
|
||||
GLTexture **ht;
|
||||
GLImage *im;
|
||||
|
||||
assert(t);
|
||||
|
||||
if (!t->prev) {
|
||||
ht = &shared_state.texture_hash_table[t->handle % TEXTURE_HASH_TABLE_SIZE];
|
||||
*ht = t->next;
|
||||
} else {
|
||||
t->prev->next = t->next;
|
||||
}
|
||||
if (t->next)
|
||||
t->next->prev = t->prev;
|
||||
|
||||
for (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
|
||||
im = &t->images[i];
|
||||
if (im->pixmap) {
|
||||
delete im->pixmap;
|
||||
im->pixmap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gl_free(t);
|
||||
}
|
||||
|
||||
GLTexture *GLContext::alloc_texture(uint h) {
|
||||
GLTexture *t, **ht;
|
||||
|
||||
t = (GLTexture *)gl_zalloc(sizeof(GLTexture));
|
||||
|
||||
ht = &shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
|
||||
|
||||
t->next = *ht;
|
||||
t->prev = nullptr;
|
||||
if (t->next)
|
||||
t->next->prev = t;
|
||||
*ht = t;
|
||||
|
||||
t->handle = h;
|
||||
t->disposed = false;
|
||||
t->versionNumber = 0;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void GLContext::glopBindTexture(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
uint texture = p[2].ui;
|
||||
GLTexture *t;
|
||||
|
||||
assert(target == TGL_TEXTURE_2D);
|
||||
(void)target;
|
||||
|
||||
t = find_texture(texture);
|
||||
if (!t) {
|
||||
t = alloc_texture(texture);
|
||||
}
|
||||
current_texture = t;
|
||||
}
|
||||
|
||||
void GLContext::glopTexImage2D(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
int level = p[2].i;
|
||||
int internalformat = p[3].i;
|
||||
int width = p[4].i;
|
||||
int height = p[5].i;
|
||||
int border = p[6].i;
|
||||
uint format = (uint)p[7].i;
|
||||
uint type = (uint)p[8].i;
|
||||
byte *pixels = (byte *)p[9].p;
|
||||
GLImage *im;
|
||||
|
||||
if (target != TGL_TEXTURE_2D)
|
||||
error("tglTexImage2D: target not handled");
|
||||
if (level < 0 || level >= MAX_TEXTURE_LEVELS)
|
||||
error("tglTexImage2D: invalid level");
|
||||
if (internalformat != TGL_RGBA && internalformat != TGL_RGB)
|
||||
error("tglTexImage2D: invalid internalformat");
|
||||
if (border != 0)
|
||||
error("tglTexImage2D: invalid border");
|
||||
|
||||
assert (current_texture);
|
||||
|
||||
current_texture->versionNumber++;
|
||||
im = ¤t_texture->images[level];
|
||||
im->xsize = _textureSize;
|
||||
im->ysize = _textureSize;
|
||||
if (im->pixmap) {
|
||||
delete im->pixmap;
|
||||
im->pixmap = nullptr;
|
||||
}
|
||||
if (pixels) {
|
||||
uint filter;
|
||||
Graphics::PixelFormat pf;
|
||||
bool found = false;
|
||||
Common::Array<struct tglColorAssociation>::const_iterator it = colorAssociationList.begin();
|
||||
for (; it != colorAssociationList.end(); it++) {
|
||||
if (it->format == format &&
|
||||
it->type == type) {
|
||||
pf = it->pf;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
error("TinyGL texture: format 0x%04x and type 0x%04x combination not supported", format, type);
|
||||
|
||||
if (width > _textureSize || height > _textureSize)
|
||||
filter = texture_mag_filter;
|
||||
else
|
||||
filter = texture_min_filter;
|
||||
switch (filter) {
|
||||
case TGL_LINEAR_MIPMAP_NEAREST:
|
||||
case TGL_LINEAR_MIPMAP_LINEAR:
|
||||
case TGL_LINEAR:
|
||||
im->pixmap = createBilinearTexelBuffer(
|
||||
pixels, pf,
|
||||
format, type,
|
||||
width, height,
|
||||
_textureSize,
|
||||
internalformat
|
||||
);
|
||||
break;
|
||||
default:
|
||||
im->pixmap = createNearestTexelBuffer(
|
||||
pixels, pf,
|
||||
format, type,
|
||||
width, height,
|
||||
_textureSize,
|
||||
internalformat
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not all tests are done
|
||||
void GLContext::glopTexEnv(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
int pname = p[2].i;
|
||||
int param = p[3].i;
|
||||
|
||||
if (target != TGL_TEXTURE_ENV) {
|
||||
error:
|
||||
error("tglTexEnv: unsupported option");
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case TGL_TEXTURE_ENV_MODE:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_DECAL ||
|
||||
param == TGL_BLEND ||
|
||||
param == TGL_ADD ||
|
||||
param == TGL_COMBINE)
|
||||
_texEnv.envMode = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_COMBINE_RGB:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_ADD)
|
||||
_texEnv.combineRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_COMBINE_ALPHA:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_ADD)
|
||||
_texEnv.combineAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_SOURCE0_RGB:
|
||||
case TGL_SOURCE1_RGB:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_SOURCE0_RGB ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_TEXTURE ||
|
||||
param == TGL_PRIMARY_COLOR ||
|
||||
param == TGL_CONSTANT)
|
||||
op->sourceRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_SOURCE0_ALPHA:
|
||||
case TGL_SOURCE1_ALPHA:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_SOURCE0_ALPHA ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_TEXTURE ||
|
||||
param == TGL_PRIMARY_COLOR ||
|
||||
param == TGL_CONSTANT)
|
||||
op->sourceAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_OPERAND0_RGB:
|
||||
case TGL_OPERAND1_RGB:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_OPERAND0_RGB ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_SRC_COLOR ||
|
||||
param == TGL_ONE_MINUS_SRC_COLOR ||
|
||||
param == TGL_SRC_ALPHA)
|
||||
op->operandRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_OPERAND0_ALPHA:
|
||||
case TGL_OPERAND1_ALPHA:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_OPERAND0_ALPHA ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_SRC_ALPHA ||
|
||||
param == TGL_ONE_MINUS_SRC_ALPHA)
|
||||
op->operandAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_TEXTURE_ENV_COLOR:
|
||||
{
|
||||
_texEnv.constR = (byte)clampf(p[4].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constG = (byte)clampf(p[5].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constB = (byte)clampf(p[6].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constA = (byte)clampf(p[7].f * 255.0f, 0, 255.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not all tests are done
|
||||
void GLContext::glopTexParameter(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
int pname = p[2].i;
|
||||
int param = p[3].i;
|
||||
|
||||
if (target != TGL_TEXTURE_2D) {
|
||||
error:
|
||||
error("tglTexParameter: unsupported option");
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case TGL_TEXTURE_WRAP_S:
|
||||
texture_wrap_s = param;
|
||||
break;
|
||||
case TGL_TEXTURE_WRAP_T:
|
||||
texture_wrap_t = param;
|
||||
break;
|
||||
case TGL_TEXTURE_MAG_FILTER:
|
||||
switch (param) {
|
||||
case TGL_NEAREST:
|
||||
case TGL_LINEAR:
|
||||
texture_mag_filter = param;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case TGL_TEXTURE_MIN_FILTER:
|
||||
switch (param) {
|
||||
case TGL_LINEAR_MIPMAP_NEAREST:
|
||||
case TGL_LINEAR_MIPMAP_LINEAR:
|
||||
case TGL_NEAREST_MIPMAP_NEAREST:
|
||||
case TGL_NEAREST_MIPMAP_LINEAR:
|
||||
case TGL_NEAREST:
|
||||
case TGL_LINEAR:
|
||||
texture_min_filter = param;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_PixelStore(TGLenum pname, TGLint param) {
|
||||
if (pname != TGL_UNPACK_ALIGNMENT || param != 1) {
|
||||
error("tglPixelStore: unsupported option");
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_GenTextures(TGLsizei n, TGLuint *textures) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
textures[i] = maxTextureName + i + 1;
|
||||
}
|
||||
maxTextureName += n;
|
||||
}
|
||||
|
||||
void GLContext::gl_DeleteTextures(TGLsizei n, const TGLuint *textures) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
TinyGL::GLTexture *t = find_texture(textures[i]);
|
||||
if (t) {
|
||||
if (t == current_texture) {
|
||||
current_texture = default_texture;
|
||||
}
|
||||
t->disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
47
graphics/tinygl/tinygl.h
Normal file
47
graphics/tinygl/tinygl.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_H
|
||||
#define GRAPHICS_TINYGL_H
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/tinygl/gl.h"
|
||||
#include "graphics/tinygl/zblit_public.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
typedef void *ContextHandle;
|
||||
|
||||
ContextHandle *createContext(int screenW, int screenH, Graphics::PixelFormat pixelFormat,
|
||||
int textureSize, bool enableStencilBuffer, bool dirtyRectsEnable,
|
||||
uint32 drawCallMemorySize = 5 * 1024 * 1024);
|
||||
void destroyContext();
|
||||
void destroyContext(ContextHandle *handle);
|
||||
void setContext(ContextHandle *handle);
|
||||
void presentBuffer();
|
||||
void presentBuffer(Common::List<Common::Rect> &dirtyAreas);
|
||||
void getSurfaceRef(Graphics::Surface &surface);
|
||||
Graphics::Surface *copyFromFrameBuffer(const Graphics::PixelFormat &dstFormat);
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
267
graphics/tinygl/vertex.cpp
Normal file
267
graphics/tinygl/vertex.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void GLContext::glopNormal(GLParam *p) {
|
||||
current_normal.X = p[1].f;
|
||||
current_normal.Y = p[2].f;
|
||||
current_normal.Z = p[3].f;
|
||||
current_normal.W = 0.0f;
|
||||
}
|
||||
|
||||
void GLContext::glopTexCoord(GLParam *p) {
|
||||
current_tex_coord.X = p[1].f;
|
||||
current_tex_coord.Y = p[2].f;
|
||||
current_tex_coord.Z = p[3].f;
|
||||
current_tex_coord.W = p[4].f;
|
||||
}
|
||||
|
||||
void GLContext::glopEdgeFlag(GLParam *p) {
|
||||
current_edge_flag = p[1].i;
|
||||
}
|
||||
|
||||
void GLContext::glopColor(GLParam *p) {
|
||||
current_color.X = p[1].f;
|
||||
current_color.Y = p[2].f;
|
||||
current_color.Z = p[3].f;
|
||||
current_color.W = p[4].f;
|
||||
|
||||
if (color_material_enabled) {
|
||||
GLParam q[7];
|
||||
q[0].op = OP_Material;
|
||||
q[1].i = current_color_material_mode;
|
||||
q[2].i = current_color_material_type;
|
||||
q[3].f = p[1].f;
|
||||
q[4].f = p[2].f;
|
||||
q[5].f = p[3].f;
|
||||
q[6].f = p[4].f;
|
||||
glopMaterial(q);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_eval_viewport() {
|
||||
GLViewport *v;
|
||||
float zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS));
|
||||
|
||||
v = &viewport;
|
||||
|
||||
// v->ymin needs to be upside down for transformation
|
||||
int ymin = fb->getPixelBufferHeight() - v->ysize - v->ymin;
|
||||
v->trans.X = (float)(((v->xsize - 0.5) / 2.0) + v->xmin);
|
||||
v->trans.Y = (float)(((v->ysize - 0.5) / 2.0) + ymin);
|
||||
v->trans.Z = (float)(((zsize - 0.5) / 2.0) + ((1 << ZB_POINT_Z_FRAC_BITS)) / 2);
|
||||
|
||||
v->scale.X = (float)((v->xsize - 0.5) / 2.0);
|
||||
// v->ysize needs to be upside down for scaling
|
||||
v->scale.Y = (float)(-(v->ysize - 0.5) / 2.0);
|
||||
v->scale.Z = (float)(-((zsize - 0.5) / 2.0));
|
||||
}
|
||||
|
||||
void GLContext::glopBegin(GLParam *p) {
|
||||
int type;
|
||||
|
||||
assert(in_begin == 0);
|
||||
|
||||
type = p[1].i;
|
||||
begin_type = type;
|
||||
in_begin = 1;
|
||||
vertex_n = 0;
|
||||
vertex_cnt = 0;
|
||||
|
||||
if (matrix_model_projection_updated) {
|
||||
if (lighting_enabled) {
|
||||
// precompute inverse modelview
|
||||
matrix_model_view_inv = *matrix_stack_ptr[0];
|
||||
matrix_model_view_inv.invert();
|
||||
matrix_model_view_inv.transpose();
|
||||
} else {
|
||||
// precompute projection matrix
|
||||
matrix_model_projection = (*matrix_stack_ptr[1]) * (*matrix_stack_ptr[0]);
|
||||
// test to accelerate computation
|
||||
matrix_model_projection_no_w_transform = 0;
|
||||
if (matrix_model_projection._m[3][0] == 0.0 && matrix_model_projection._m[3][1] == 0.0 && matrix_model_projection._m[3][2] == 0.0)
|
||||
matrix_model_projection_no_w_transform = 1;
|
||||
}
|
||||
|
||||
matrix_model_projection_updated = 0;
|
||||
}
|
||||
// test if the texture matrix is not Identity
|
||||
apply_texture_matrix = !matrix_stack_ptr[2]->isIdentity();
|
||||
|
||||
// viewport
|
||||
if (viewport.updated) {
|
||||
gl_eval_viewport();
|
||||
viewport.updated = 0;
|
||||
}
|
||||
// triangle drawing functions
|
||||
if (render_mode == TGL_SELECT) {
|
||||
draw_triangle_front = gl_draw_triangle_select;
|
||||
draw_triangle_back = gl_draw_triangle_select;
|
||||
} else {
|
||||
switch (polygon_mode_front) {
|
||||
case TGL_POINT:
|
||||
draw_triangle_front = gl_draw_triangle_point;
|
||||
break;
|
||||
case TGL_LINE:
|
||||
draw_triangle_front = gl_draw_triangle_line;
|
||||
break;
|
||||
default:
|
||||
draw_triangle_front = gl_draw_triangle_fill;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (polygon_mode_back) {
|
||||
case TGL_POINT:
|
||||
draw_triangle_back = gl_draw_triangle_point;
|
||||
break;
|
||||
case TGL_LINE:
|
||||
draw_triangle_back = gl_draw_triangle_line;
|
||||
break;
|
||||
default:
|
||||
draw_triangle_back = gl_draw_triangle_fill;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// coords, tranformation, clip code and projection
|
||||
// TODO : handle all cases
|
||||
void GLContext::gl_vertex_transform(GLVertex *v) {
|
||||
Matrix4 *m;
|
||||
|
||||
if (lighting_enabled || fog_enabled) {
|
||||
// eye coordinates needed for lighting and fog
|
||||
m = matrix_stack_ptr[0];
|
||||
m->transform3x4(v->coord, v->ec);
|
||||
}
|
||||
|
||||
if (fog_enabled) {
|
||||
gl_calc_fog_factor(v);
|
||||
}
|
||||
|
||||
if (lighting_enabled) {
|
||||
// projection coordinates
|
||||
m = matrix_stack_ptr[1];
|
||||
m->transform(v->ec, v->pc);
|
||||
|
||||
m = &matrix_model_view_inv;
|
||||
m->transform3x3(current_normal, v->normal);
|
||||
|
||||
if (normalize_enabled) {
|
||||
v->normal.normalize();
|
||||
}
|
||||
} else {
|
||||
// no eye coordinates needed, no normal
|
||||
// NOTE: W = 1 is assumed
|
||||
m = &matrix_model_projection;
|
||||
m->transform3x4(v->coord, v->pc);
|
||||
|
||||
if (matrix_model_projection_no_w_transform) {
|
||||
v->pc.W = (m->_m[3][3]);
|
||||
}
|
||||
v->normal.X = v->normal.Y = v->normal.Z = 0;
|
||||
v->ec.X = v->ec.Y = v->ec.Z = v->ec.W = 0;
|
||||
}
|
||||
|
||||
v->clip_code = gl_clipcode(v->pc.X, v->pc.Y, v->pc.Z, v->pc.W);
|
||||
}
|
||||
|
||||
void GLContext::glopVertex(GLParam *p) {
|
||||
GLVertex *v;
|
||||
int n, cnt;
|
||||
|
||||
assert(in_begin != 0);
|
||||
|
||||
n = vertex_n;
|
||||
cnt = vertex_cnt;
|
||||
cnt++;
|
||||
vertex_cnt = cnt;
|
||||
|
||||
// quick fix to avoid crashes on large polygons
|
||||
if (n >= vertex_max) {
|
||||
GLVertex *newarray;
|
||||
vertex_max <<= 1; // just double size
|
||||
newarray = (GLVertex *)gl_realloc(vertex, sizeof(GLVertex) * vertex_max);
|
||||
if (!newarray) {
|
||||
error("unable to allocate GLVertex array.");
|
||||
}
|
||||
vertex = newarray;
|
||||
}
|
||||
// new vertex entry
|
||||
v = &vertex[n];
|
||||
n++;
|
||||
|
||||
v->coord.X = p[1].f;
|
||||
v->coord.Y = p[2].f;
|
||||
v->coord.Z = p[3].f;
|
||||
v->coord.W = p[4].f;
|
||||
|
||||
gl_vertex_transform(v);
|
||||
|
||||
// color
|
||||
|
||||
if (lighting_enabled) {
|
||||
gl_shade_vertex(v);
|
||||
} else {
|
||||
v->color = current_color;
|
||||
}
|
||||
|
||||
// tex coords
|
||||
|
||||
if (texture_2d_enabled) {
|
||||
if (apply_texture_matrix) {
|
||||
matrix_stack_ptr[2]->transform(current_tex_coord, v->tex_coord);
|
||||
} else {
|
||||
v->tex_coord = current_tex_coord;
|
||||
}
|
||||
}
|
||||
// precompute the mapping to the viewport
|
||||
if (v->clip_code == 0)
|
||||
gl_transform_to_viewport(v);
|
||||
|
||||
// edge flag
|
||||
|
||||
v->edge_flag = current_edge_flag;
|
||||
|
||||
vertex_n = n;
|
||||
}
|
||||
|
||||
void GLContext::glopEnd(GLParam *) {
|
||||
assert(in_begin == 1);
|
||||
|
||||
if (vertex_cnt > 0) {
|
||||
issueDrawCall(new RasterizationDrawCall());
|
||||
}
|
||||
|
||||
in_begin = 0;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
855
graphics/tinygl/zblit.cpp
Normal file
855
graphics/tinygl/zblit.cpp
Normal file
@@ -0,0 +1,855 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
#include "graphics/tinygl/zblit.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/pixelbuffer.h"
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
#include "graphics/tinygl/gl.h"
|
||||
|
||||
#include "graphics/blit.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
Common::Point transformPoint(float x, float y, int rotation);
|
||||
Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY);
|
||||
|
||||
struct BlitImage {
|
||||
public:
|
||||
BlitImage() : _isDisposed(false), _version(0), _binaryTransparent(false), _opaque(true), _zBuffer(false), _refcount(1) { }
|
||||
|
||||
void loadData(const Graphics::Surface &surface, uint32 colorKey, bool applyColorKey, bool zBuffer) {
|
||||
_lines.clear();
|
||||
|
||||
_zBuffer = zBuffer;
|
||||
if (_zBuffer) {
|
||||
_surface.copyFrom(surface);
|
||||
return;
|
||||
}
|
||||
|
||||
int size = surface.w * surface.h;
|
||||
Graphics::PixelBuffer buffer(surface.format, (byte *)const_cast<void *>(surface.getPixels()));
|
||||
|
||||
_opaque = true;
|
||||
if (surface.format.aBits() > 0) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
uint8 r, g, b, a;
|
||||
buffer.getARGBAt(x, a, r, g, b);
|
||||
if (a != 0xFF) {
|
||||
_opaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_opaque && !applyColorKey) {
|
||||
GLContext *c = gl_get_context();
|
||||
_surface.convertFrom(surface, c->fb->getPixelFormat());
|
||||
|
||||
_binaryTransparent = false;
|
||||
} else {
|
||||
const Graphics::PixelFormat textureFormat = Graphics::PixelFormat::createFormatRGBA32();
|
||||
_surface.convertFrom(surface, textureFormat);
|
||||
|
||||
Graphics::PixelBuffer dataBuffer(textureFormat, (byte *)const_cast<void *>(_surface.getPixels()));
|
||||
|
||||
if (applyColorKey) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (buffer.getValueAt(x) == colorKey) {
|
||||
// Color keyed pixels become transparent white.
|
||||
dataBuffer.setPixelAt(x, 0, 255, 255, 255);
|
||||
_opaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create opaque lines data.
|
||||
// A line of pixels can not wrap more that one line of the image, since it would break
|
||||
// blitting of bitmaps with a non-zero x position.
|
||||
Graphics::PixelBuffer srcBuf = dataBuffer;
|
||||
_binaryTransparent = true;
|
||||
for (int y = 0; y < surface.h; y++) {
|
||||
int start = -1;
|
||||
for (int x = 0; x < surface.w; ++x) {
|
||||
// We found a transparent pixel, so save a line from 'start' to the pixel before this.
|
||||
uint8 r, g, b, a;
|
||||
srcBuf.getARGBAt(x, a, r, g, b);
|
||||
if (a != 0 && a != 0xFF) {
|
||||
_binaryTransparent = false;
|
||||
}
|
||||
if (a == 0 && start >= 0) {
|
||||
_lines.push_back(Line(start, y, x - start, srcBuf.getRawBuffer(start), textureFormat));
|
||||
start = -1;
|
||||
} else if (a != 0 && start == -1) {
|
||||
start = x;
|
||||
}
|
||||
}
|
||||
// end of the bitmap line. if start is an actual pixel save the line.
|
||||
if (start >= 0) {
|
||||
_lines.push_back(Line(start, y, surface.w - start, srcBuf.getRawBuffer(start), textureFormat));
|
||||
}
|
||||
srcBuf.shiftBy(surface.w);
|
||||
}
|
||||
}
|
||||
|
||||
_version++;
|
||||
}
|
||||
|
||||
int getVersion() const {
|
||||
return _version;
|
||||
}
|
||||
|
||||
~BlitImage() {
|
||||
_surface.free();
|
||||
}
|
||||
|
||||
struct Line {
|
||||
int _x;
|
||||
int _y;
|
||||
int _bpp;
|
||||
int _length;
|
||||
byte *_pixels;
|
||||
|
||||
Line() : _x(0), _y(0), _length(0), _pixels(nullptr) { }
|
||||
Line(int x, int y, int length, byte *pixels, const Graphics::PixelFormat &textureFormat) :
|
||||
_x(x), _y(y), _bpp(gl_get_context()->fb->getPixelBufferBpp()), _length(length) {
|
||||
_pixels = (byte *)gl_zalloc(_length * _bpp);
|
||||
Graphics::crossBlit(_pixels, pixels, _length * _bpp, _length * _bpp, _length, 1,
|
||||
gl_get_context()->fb->getPixelFormat(), textureFormat);
|
||||
}
|
||||
|
||||
Line &operator=(const Line &other) {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
_x = other._x;
|
||||
_y = other._y;
|
||||
if (_length != other._length || _bpp != other._bpp) {
|
||||
_pixels = (byte *)gl_realloc(_pixels, other._length * other._bpp);
|
||||
_length = other._length;
|
||||
_bpp = other._bpp;
|
||||
}
|
||||
memcpy(_pixels, other._pixels, _length * _bpp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Line(const Line& other) : _x(other._x), _y(other._y), _bpp(other._bpp), _length(other._length) {
|
||||
_pixels = (byte *)gl_zalloc(_length * _bpp);
|
||||
memcpy(_pixels, other._pixels, _length * _bpp);
|
||||
}
|
||||
|
||||
~Line() {
|
||||
gl_free(_pixels);
|
||||
}
|
||||
};
|
||||
|
||||
bool clipBlitImage(TinyGL::GLContext *c, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &width, int &height, int &dstX, int &dstY, int &clampWidth, int &clampHeight) {
|
||||
if (srcWidth == 0 || srcHeight == 0) {
|
||||
srcWidth = _surface.w;
|
||||
srcHeight = _surface.h;
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
width = srcWidth;
|
||||
height = srcHeight;
|
||||
}
|
||||
|
||||
const Common::Rect &clippingRect = c->fb->getClippingRectangle();
|
||||
|
||||
if (dstX >= clippingRect.right || dstY >= clippingRect.bottom)
|
||||
return false;
|
||||
|
||||
if (dstX + width < clippingRect.left || dstY + height < clippingRect.top) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dstX < clippingRect.left) {
|
||||
srcX += (clippingRect.left - dstX);
|
||||
width -= (clippingRect.left - dstX);
|
||||
dstX = clippingRect.left;
|
||||
}
|
||||
|
||||
if (dstY < clippingRect.top) {
|
||||
srcY += (clippingRect.top - dstY);
|
||||
height -= (clippingRect.top - dstY);
|
||||
dstY = clippingRect.top;
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dstX + width >= clippingRect.right) {
|
||||
clampWidth = clippingRect.right - dstX;
|
||||
} else {
|
||||
clampWidth = width;
|
||||
}
|
||||
|
||||
if (dstY + height >= clippingRect.bottom) {
|
||||
clampHeight = clippingRect.bottom - dstY;
|
||||
} else {
|
||||
clampHeight = height;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Blits an image to the z buffer.
|
||||
// The function only supports clipped blitting without any type of transformation or tinting.
|
||||
void tglBlitZBuffer(int dstX, int dstY) {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
assert(_zBuffer);
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
int width = _surface.w, height = _surface.h;
|
||||
int srcWidth = 0, srcHeight = 0;
|
||||
int srcX = 0, srcY = 0;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
int fbWidth = c->fb->getPixelBufferWidth();
|
||||
|
||||
Graphics::PixelBuffer srcBuf(_surface.format, (byte *)const_cast<void *>(_surface.getPixels())); // Blit image buffer
|
||||
Graphics::PixelBuffer dstBuf(_surface.format, (byte *)const_cast<uint *>(c->fb->getZBuffer())); // TinyGL z buffer
|
||||
|
||||
srcBuf.shiftBy(srcY * _surface.w);
|
||||
|
||||
dstBuf.shiftBy(dstY * fbWidth);
|
||||
for (int y = 0; y < clampHeight; y++) {
|
||||
dstBuf.copyBuffer(dstX, srcX, clampWidth, srcBuf);
|
||||
dstBuf.shiftBy(fbWidth);
|
||||
srcBuf.shiftBy(_surface.w);
|
||||
}
|
||||
}
|
||||
|
||||
void tglBlitOpaque(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight);
|
||||
|
||||
template <bool kDisableColoring, bool kDisableBlending, bool kEnableAlphaBlending>
|
||||
void tglBlitRLE(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
|
||||
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void tglBlitSimple(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
|
||||
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void tglBlitScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint);
|
||||
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void tglBlitRotoScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation,
|
||||
int originX, int originY, float aTint, float rTint, float gTint, float bTint);
|
||||
|
||||
//Utility function that calls the correct blitting function.
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kDisableTransform, bool kFlipVertical, bool kFlipHorizontal, bool kEnableAlphaBlending, bool kEnableOpaqueBlit>
|
||||
void tglBlitGeneric(const BlitTransform &transform) {
|
||||
assert(!_zBuffer);
|
||||
|
||||
if (kDisableTransform) {
|
||||
if (kEnableOpaqueBlit && kDisableColoring && kFlipVertical == false && kFlipHorizontal == false) {
|
||||
tglBlitOpaque(transform._destinationRectangle.left, transform._destinationRectangle.top,
|
||||
transform._sourceRectangle.left, transform._sourceRectangle.top,
|
||||
transform._sourceRectangle.width() , transform._sourceRectangle.height());
|
||||
} else if ((kDisableBlending || kEnableAlphaBlending) && kFlipVertical == false && kFlipHorizontal == false) {
|
||||
tglBlitRLE<kDisableColoring, kDisableBlending, kEnableAlphaBlending>(transform._destinationRectangle.left,
|
||||
transform._destinationRectangle.top, transform._sourceRectangle.left, transform._sourceRectangle.top,
|
||||
transform._sourceRectangle.width() , transform._sourceRectangle.height(), transform._aTint,
|
||||
transform._rTint, transform._gTint, transform._bTint);
|
||||
} else {
|
||||
tglBlitSimple<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left,
|
||||
transform._destinationRectangle.top, transform._sourceRectangle.left, transform._sourceRectangle.top,
|
||||
transform._sourceRectangle.width() , transform._sourceRectangle.height(),
|
||||
transform._aTint, transform._rTint, transform._gTint, transform._bTint);
|
||||
}
|
||||
} else {
|
||||
if (transform._rotation == 0) {
|
||||
tglBlitScale<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left,
|
||||
transform._destinationRectangle.top, transform._destinationRectangle.width(), transform._destinationRectangle.height(),
|
||||
transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width(), transform._sourceRectangle.height(),
|
||||
transform._aTint, transform._rTint, transform._gTint, transform._bTint);
|
||||
} else {
|
||||
tglBlitRotoScale<kDisableBlending, kDisableColoring, kFlipVertical, kFlipHorizontal>(transform._destinationRectangle.left,
|
||||
transform._destinationRectangle.top, transform._destinationRectangle.width(), transform._destinationRectangle.height(),
|
||||
transform._sourceRectangle.left, transform._sourceRectangle.top, transform._sourceRectangle.width(),
|
||||
transform._sourceRectangle.height(), transform._rotation, transform._originX, transform._originY, transform._aTint,
|
||||
transform._rTint, transform._gTint, transform._bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getWidth() const { return _surface.w; }
|
||||
int getHeight() const { return _surface.h; }
|
||||
void incRefCount() { _refcount++; }
|
||||
void dispose() { if (--_refcount == 0) _isDisposed = true; }
|
||||
bool isDisposed() const { return _isDisposed; }
|
||||
bool isOpaque() const { return _opaque; }
|
||||
private:
|
||||
bool _isDisposed;
|
||||
bool _binaryTransparent;
|
||||
bool _opaque;
|
||||
bool _zBuffer;
|
||||
Common::Array<Line> _lines;
|
||||
Graphics::Surface _surface;
|
||||
int _version;
|
||||
int _refcount;
|
||||
};
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
|
||||
void tglGetBlitImageSize(TinyGL::BlitImage *blitImage, int &width, int &height) {
|
||||
width = blitImage->getWidth();
|
||||
height = blitImage->getHeight();
|
||||
}
|
||||
|
||||
void tglIncBlitImageRef(TinyGL::BlitImage *blitImage) {
|
||||
blitImage->incRefCount();
|
||||
}
|
||||
|
||||
int tglGetBlitImageVersion(TinyGL::BlitImage *blitImage) {
|
||||
return blitImage->getVersion();
|
||||
}
|
||||
|
||||
TinyGL::BlitImage *tglGenBlitImage() {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
TinyGL::BlitImage *image = new TinyGL::BlitImage();
|
||||
c->_blitImages.push_back(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
void tglUploadBlitImage(TinyGL::BlitImage *blitImage, const Graphics::Surface& surface, uint32 colorKey, bool applyColorKey, bool zBuffer) {
|
||||
if (blitImage != nullptr) {
|
||||
blitImage->loadData(surface, colorKey, applyColorKey, zBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void tglDeleteBlitImage(TinyGL::BlitImage *blitImage) {
|
||||
if (blitImage != nullptr) {
|
||||
blitImage->dispose();
|
||||
}
|
||||
}
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
void BlitImage::tglBlitOpaque(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
int width = srcWidth, height = srcHeight;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
int fbPitch = c->fb->getPixelBufferPitch();
|
||||
int fbBpp = c->fb->getPixelBufferBpp();
|
||||
byte *fbBuf = c->fb->getPixelBuffer() + (dstX * fbBpp) + (dstY * fbPitch);
|
||||
|
||||
Graphics::crossBlit(fbBuf, (const byte *)_surface.getBasePtr(srcX, srcY),
|
||||
fbPitch, _surface.pitch, clampWidth, clampHeight,
|
||||
c->fb->getPixelFormat(), _surface.format);
|
||||
}
|
||||
|
||||
// This function uses RLE encoding to skip transparent bitmap parts
|
||||
// This blit only supports tinting but it will fall back to simpleBlit
|
||||
// if flipping is required (or anything more complex than that, including rotationd and scaling).
|
||||
template <bool kDisableColoring, bool kDisableBlending, bool kEnableAlphaBlending>
|
||||
void BlitImage::tglBlitRLE(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
int width = srcWidth, height = srcHeight;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
if (aTint <= 0.0f)
|
||||
return;
|
||||
|
||||
int fbWidth = c->fb->getPixelBufferWidth();
|
||||
|
||||
Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
|
||||
srcBuf.shiftBy(srcX + (srcY * _surface.w));
|
||||
|
||||
Graphics::PixelBuffer dstBuf(c->fb->getPixelFormat(), c->fb->getPixelBuffer());
|
||||
dstBuf.shiftBy(dstY * fbWidth + dstX);
|
||||
|
||||
int kBytesPerPixel = c->fb->getPixelFormat().bytesPerPixel;
|
||||
|
||||
uint32 lineIndex = 0;
|
||||
int maxY = srcY + clampHeight;
|
||||
int maxX = srcX + clampWidth;
|
||||
while (lineIndex < _lines.size() && _lines[lineIndex]._y < srcY) {
|
||||
lineIndex++;
|
||||
}
|
||||
|
||||
if (_opaque) { // This is the degenerate case of RLE where the whole image is affected
|
||||
for (int y = 0; y < clampHeight; y++) {
|
||||
if (kDisableColoring) {
|
||||
memcpy(dstBuf.getRawBuffer(y * fbWidth),
|
||||
srcBuf.getRawBuffer(y * _surface.w), clampWidth * kBytesPerPixel);
|
||||
} else {
|
||||
for(int x = 0; x < clampWidth; x++) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
srcBuf.getARGBAt(y * _surface.w + x, aDst, rDst, gDst, bDst);
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_binaryTransparent || (kDisableBlending || !kEnableAlphaBlending)) { // If bitmap is binary transparent or if we need complex forms of blending (not just alpha) we need to use writePixel, which is slower
|
||||
while (lineIndex < _lines.size() && _lines[lineIndex]._y < maxY) {
|
||||
const BlitImage::Line &l = _lines[lineIndex];
|
||||
if (l._x < maxX && l._x + l._length > srcX) {
|
||||
int length = l._length;
|
||||
int skipStart = (l._x < srcX) ? (srcX - l._x) : 0;
|
||||
length -= skipStart;
|
||||
int skipEnd = (l._x + l._length > maxX) ? (l._x + l._length - maxX) : 0;
|
||||
length -= skipEnd;
|
||||
int xStart = MAX(l._x - srcX, 0);
|
||||
if (kDisableColoring) {
|
||||
memcpy(dstBuf.getRawBuffer((l._y - srcY) * fbWidth + xStart),
|
||||
l._pixels + skipStart * kBytesPerPixel, length * kBytesPerPixel);
|
||||
} else {
|
||||
for(int x = xStart; x < xStart + length; x++) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
srcBuf.getARGBAt((l._y - srcY) * _surface.w + x, aDst, rDst, gDst, bDst);
|
||||
c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
lineIndex++;
|
||||
}
|
||||
} else { // Otherwise can use setPixel in some cases which speeds up things quite a bit
|
||||
while (lineIndex < _lines.size() && _lines[lineIndex]._y < maxY) {
|
||||
const BlitImage::Line &l = _lines[lineIndex];
|
||||
if (l._x < maxX && l._x + l._length > srcX) {
|
||||
int length = l._length;
|
||||
int skipStart = (l._x < srcX) ? (srcX - l._x) : 0;
|
||||
length -= skipStart;
|
||||
int skipEnd = (l._x + l._length > maxX) ? (l._x + l._length - maxX) : 0;
|
||||
length -= skipEnd;
|
||||
int xStart = MAX(l._x - srcX, 0);
|
||||
if (kDisableColoring && (kEnableAlphaBlending == false || kDisableBlending)) {
|
||||
memcpy(dstBuf.getRawBuffer((l._y - srcY) * fbWidth + xStart),
|
||||
l._pixels + skipStart * kBytesPerPixel, length * kBytesPerPixel);
|
||||
} else {
|
||||
for(int x = xStart; x < xStart + length; x++) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
srcBuf.getARGBAt((l._y - srcY) * _surface.w + x, aDst, rDst, gDst, bDst);
|
||||
if (kDisableColoring) {
|
||||
if (aDst != 0xFF) {
|
||||
c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
} else {
|
||||
dstBuf.setPixelAt(x + (l._y - srcY) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
}
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + (l._y - srcY)) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lineIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This blit function is called when flipping is needed but transformation isn't.
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void BlitImage::tglBlitSimple(int dstX, int dstY, int srcX, int srcY, int srcWidth, int srcHeight, float aTint, float rTint, float gTint, float bTint) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
int width = srcWidth, height = srcHeight;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
|
||||
|
||||
if (kFlipVertical) {
|
||||
srcBuf.shiftBy(((srcHeight - srcY - 1) * _surface.w));
|
||||
} else {
|
||||
srcBuf.shiftBy((srcY * _surface.w));
|
||||
}
|
||||
|
||||
Graphics::PixelBuffer dstBuf(c->fb->getPixelFormat(), c->fb->getPixelBuffer());
|
||||
int fbWidth = c->fb->getPixelBufferWidth();
|
||||
|
||||
for (int y = 0; y < clampHeight; y++) {
|
||||
for (int x = 0; x < clampWidth; ++x) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
if (kFlipHorizontal) {
|
||||
srcBuf.getARGBAt(srcX + clampWidth - x, aDst, rDst, gDst, bDst);
|
||||
} else {
|
||||
srcBuf.getARGBAt(srcX + x, aDst, rDst, gDst, bDst);
|
||||
}
|
||||
|
||||
// Those branches are needed to favor speed: avoiding writePixel always yield a huge performance boost when blitting images.
|
||||
if (kDisableColoring) {
|
||||
if (kDisableBlending && aDst != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
}
|
||||
} else {
|
||||
if (kDisableBlending && aDst * aTint != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (kFlipVertical) {
|
||||
srcBuf.shiftBy(-_surface.w);
|
||||
} else {
|
||||
srcBuf.shiftBy(_surface.w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called when scale is needed: it uses a simple nearest
|
||||
// filter to scale the blit image before copying it to the screen.
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void BlitImage::tglBlitScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight,
|
||||
float aTint, float rTint, float gTint, float bTint) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
|
||||
srcBuf.shiftBy(srcX + (srcY * _surface.w));
|
||||
|
||||
Graphics::PixelBuffer dstBuf(c->fb->getPixelFormat(), c->fb->getPixelBuffer());
|
||||
int fbWidth = c->fb->getPixelBufferWidth();
|
||||
|
||||
for (int y = 0; y < clampHeight; y++) {
|
||||
for (int x = 0; x < clampWidth; ++x) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
int xSource, ySource;
|
||||
if (kFlipVertical) {
|
||||
ySource = clampHeight - y - 1;
|
||||
} else {
|
||||
ySource = y;
|
||||
}
|
||||
|
||||
if (kFlipHorizontal) {
|
||||
xSource = clampWidth - x - 1;
|
||||
} else {
|
||||
xSource = x;
|
||||
}
|
||||
|
||||
srcBuf.getARGBAt(((ySource * srcHeight) / height) * _surface.w + ((xSource * srcWidth) / width), aDst, rDst, gDst, bDst);
|
||||
|
||||
if (kDisableColoring) {
|
||||
if (kDisableBlending && aDst != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
}
|
||||
} else {
|
||||
if (kDisableBlending && aDst * aTint != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
The below two functions are adapted from SDL_rotozoom.c,
|
||||
taken from SDL_gfx-2.0.18.
|
||||
|
||||
Its copyright notice:
|
||||
|
||||
=============================================================================
|
||||
SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
|
||||
|
||||
Copyright (C) 2001-2012 Andreas Schiffler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
Andreas Schiffler -- aschiffler at ferzkopp dot net
|
||||
=============================================================================
|
||||
|
||||
|
||||
The functions have been adapted for different structures and coordinate
|
||||
systems.
|
||||
|
||||
*/
|
||||
|
||||
template <bool kDisableBlending, bool kDisableColoring, bool kFlipVertical, bool kFlipHorizontal>
|
||||
void BlitImage::tglBlitRotoScale(int dstX, int dstY, int width, int height, int srcX, int srcY, int srcWidth, int srcHeight, int rotation,
|
||||
int originX, int originY, float aTint, float rTint, float gTint, float bTint) {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
int clampWidth, clampHeight;
|
||||
if (clipBlitImage(c, srcX, srcY, srcWidth, srcHeight, width, height, dstX, dstY, clampWidth, clampHeight) == false)
|
||||
return;
|
||||
|
||||
Graphics::PixelBuffer srcBuf(_surface.format, (byte *)_surface.getPixels());
|
||||
srcBuf.shiftBy(srcX + (srcY * _surface.w));
|
||||
int fbWidth = c->fb->getPixelBufferWidth();
|
||||
|
||||
Graphics::PixelBuffer dstBuf(c->fb->getPixelFormat(), c->fb->getPixelBuffer());
|
||||
|
||||
// Transform destination rectangle accordingly.
|
||||
Common::Rect destinationRectangle = rotateRectangle(dstX, dstY, width, height, rotation, originX, originY);
|
||||
|
||||
if (dstX + destinationRectangle.width() > fbWidth)
|
||||
clampWidth = fbWidth - dstX;
|
||||
else
|
||||
clampWidth = destinationRectangle.width();
|
||||
if (dstY + destinationRectangle.height() > c->fb->getPixelBufferHeight())
|
||||
clampHeight = c->fb->getPixelBufferHeight() - dstY;
|
||||
else
|
||||
clampHeight = destinationRectangle.height();
|
||||
|
||||
uint32 invAngle = 360 - (rotation % 360);
|
||||
float invCos = cos(invAngle * (float)M_PI / 180.0f);
|
||||
float invSin = sin(invAngle * (float)M_PI / 180.0f);
|
||||
|
||||
int icosx = (int)(invCos * (65536.0f * srcWidth / width));
|
||||
int isinx = (int)(invSin * (65536.0f * srcWidth / width));
|
||||
int icosy = (int)(invCos * (65536.0f * srcHeight / height));
|
||||
int isiny = (int)(invSin * (65536.0f * srcHeight / height));
|
||||
|
||||
int xd = (srcX + originX) << 16;
|
||||
int yd = (srcY + originY) << 16;
|
||||
int cx = originX * ((float)width / srcWidth);
|
||||
int cy = originY * ((float)height / srcHeight);
|
||||
|
||||
int ax = -icosx * cx;
|
||||
int ay = -isiny * cx;
|
||||
int sw = width - 1;
|
||||
int sh = height - 1;
|
||||
|
||||
for (int y = 0; y < clampHeight; y++) {
|
||||
int t = cy - y;
|
||||
int sdx = ax + (isinx * t) + xd;
|
||||
int sdy = ay - (icosy * t) + yd;
|
||||
for (int x = 0; x < clampWidth; ++x) {
|
||||
byte aDst, rDst, gDst, bDst;
|
||||
|
||||
int dx = (sdx >> 16);
|
||||
int dy = (sdy >> 16);
|
||||
|
||||
if (kFlipHorizontal) {
|
||||
dx = sw - dx;
|
||||
}
|
||||
|
||||
if (kFlipVertical) {
|
||||
dy = sh - dy;
|
||||
}
|
||||
|
||||
if ((dx >= 0) && (dy >= 0) && (dx < srcWidth) && (dy < srcHeight)) {
|
||||
srcBuf.getARGBAt(dy * _surface.w + dx, aDst, rDst, gDst, bDst);
|
||||
if (kDisableColoring) {
|
||||
if (kDisableBlending && aDst != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst, rDst, gDst, bDst);
|
||||
}
|
||||
} else {
|
||||
if (kDisableBlending && aDst * aTint != 0) {
|
||||
dstBuf.setPixelAt((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
} else {
|
||||
c->fb->writePixel((dstX + x) + (dstY + y) * fbWidth, aDst * aTint, rDst * rTint, gDst * gTint, bDst * bTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
sdx += icosx;
|
||||
sdy += isiny;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
void tglBlit(TinyGL::BlitImage *blitImage, int x, int y) {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
TinyGL::BlitTransform transform(x, y);
|
||||
c->issueDrawCall(new TinyGL::BlittingDrawCall(blitImage, transform, TinyGL::BlittingDrawCall::BlitMode_Regular));
|
||||
}
|
||||
|
||||
void tglBlit(TinyGL::BlitImage *blitImage, const TinyGL::BlitTransform &transform) {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
c->issueDrawCall(new TinyGL::BlittingDrawCall(blitImage, transform, TinyGL::BlittingDrawCall::BlitMode_Regular));
|
||||
}
|
||||
|
||||
void tglBlitFast(TinyGL::BlitImage *blitImage, int x, int y) {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
TinyGL::BlitTransform transform(x, y);
|
||||
c->issueDrawCall(new TinyGL::BlittingDrawCall(blitImage, transform, TinyGL::BlittingDrawCall::BlitMode_Fast));
|
||||
}
|
||||
|
||||
void tglBlitZBuffer(TinyGL::BlitImage *blitImage, int x, int y) {
|
||||
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
||||
TinyGL::BlitTransform transform(x, y);
|
||||
c->issueDrawCall(new TinyGL::BlittingDrawCall(blitImage, transform, TinyGL::BlittingDrawCall::BlitMode_ZBuffer));
|
||||
}
|
||||
|
||||
|
||||
namespace TinyGL {
|
||||
namespace Internal {
|
||||
|
||||
template <bool kEnableAlphaBlending, bool kEnableOpaqueBlit, bool kDisableColor, bool kDisableTransform, bool kDisableBlend>
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform) {
|
||||
if (transform._flipHorizontally) {
|
||||
if (transform._flipVertically) {
|
||||
blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, true, true, kEnableAlphaBlending, kEnableOpaqueBlit>(transform);
|
||||
} else {
|
||||
blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, false, true, kEnableAlphaBlending, kEnableOpaqueBlit>(transform);
|
||||
}
|
||||
} else if (transform._flipVertically) {
|
||||
blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, true, false, kEnableAlphaBlending, kEnableOpaqueBlit>(transform);
|
||||
} else {
|
||||
blitImage->tglBlitGeneric<kDisableBlend, kDisableColor, kDisableTransform, false, false, kEnableAlphaBlending, kEnableOpaqueBlit>(transform);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaBlending, bool kEnableOpaqueBlit, bool kDisableColor, bool kDisableTransform>
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableBlend) {
|
||||
if (disableBlend) {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, kDisableColor, kDisableTransform, true>(blitImage, transform);
|
||||
} else {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, kDisableColor, kDisableTransform, false>(blitImage, transform);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaBlending, bool kEnableOpaqueBlit, bool kDisableColor>
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableTransform, bool disableBlend) {
|
||||
if (disableTransform) {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, kDisableColor, true>(blitImage, transform, disableBlend);
|
||||
} else {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, kDisableColor, false>(blitImage, transform, disableBlend);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaBlending, bool kEnableOpaqueBlit>
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool disableColor, bool disableTransform, bool disableBlend) {
|
||||
if (disableColor) {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, true>(blitImage, transform, disableTransform, disableBlend);
|
||||
} else {
|
||||
tglBlit<kEnableAlphaBlending, kEnableOpaqueBlit, false>(blitImage, transform, disableTransform, disableBlend);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaBlending>
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform, bool enableOpaqueBlit, bool disableColor, bool disableTransform, bool disableBlend) {
|
||||
if (enableOpaqueBlit) {
|
||||
tglBlit<kEnableAlphaBlending, true>(blitImage, transform, disableColor, disableTransform, disableBlend);
|
||||
} else {
|
||||
tglBlit<kEnableAlphaBlending, false>(blitImage, transform, disableColor, disableTransform, disableBlend);
|
||||
}
|
||||
}
|
||||
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform) {
|
||||
GLContext *c = gl_get_context();
|
||||
bool disableColor = transform._aTint == 1.0f && transform._bTint == 1.0f && transform._gTint == 1.0f && transform._rTint == 1.0f;
|
||||
bool disableTransform = transform._destinationRectangle.width() == 0 && transform._destinationRectangle.height() == 0 && transform._rotation == 0;
|
||||
bool disableBlend = c->blending_enabled == false;
|
||||
bool enableAlphaBlending = c->source_blending_factor == TGL_SRC_ALPHA && c->destination_blending_factor == TGL_ONE_MINUS_SRC_ALPHA;
|
||||
bool enableOpaqueBlit = blitImage->isOpaque()
|
||||
&& (c->source_blending_factor == TGL_ONE || c->source_blending_factor == TGL_SRC_ALPHA)
|
||||
&& (c->destination_blending_factor == TGL_ZERO || c->destination_blending_factor == TGL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (enableAlphaBlending) {
|
||||
tglBlit<true>(blitImage, transform, enableOpaqueBlit, disableColor, disableTransform, disableBlend);
|
||||
} else {
|
||||
tglBlit<false>(blitImage, transform, enableOpaqueBlit, disableColor, disableTransform, disableBlend);
|
||||
}
|
||||
}
|
||||
|
||||
void tglBlitFast(BlitImage *blitImage, int x, int y) {
|
||||
BlitTransform transform(x, y);
|
||||
if (blitImage->isOpaque()) {
|
||||
blitImage->tglBlitGeneric<true, true, true, false, false, false, true>(transform);
|
||||
} else {
|
||||
blitImage->tglBlitGeneric<true, true, true, false, false, false, false>(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void tglBlitZBuffer(BlitImage *blitImage, int x, int y) {
|
||||
blitImage->tglBlitZBuffer(x, y);
|
||||
}
|
||||
|
||||
void tglCleanupImages() {
|
||||
GLContext *c = gl_get_context();
|
||||
Common::List<BlitImage *>::iterator it = c->_blitImages.begin();
|
||||
while (it != c->_blitImages.end()) {
|
||||
if ((*it)->isDisposed()) {
|
||||
delete (*it);
|
||||
it = c->_blitImages.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Internal
|
||||
|
||||
Common::Point transformPoint(float x, float y, int rotation) {
|
||||
float rotateRad = rotation * (float)M_PI / 180.0f;
|
||||
Common::Point newPoint;
|
||||
newPoint.x = x * cos(rotateRad) - y * sin(rotateRad);
|
||||
newPoint.y = x * sin(rotateRad) + y * cos(rotateRad);
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
Common::Rect rotateRectangle(int x, int y, int width, int height, int rotation, int originX, int originY) {
|
||||
Common::Point nw, ne, sw, se;
|
||||
nw = transformPoint(x - originX, y - originY, rotation);
|
||||
ne = transformPoint(x + width - originX, y - originY, rotation);
|
||||
sw = transformPoint(x + width - originX, y + height - originY, rotation);
|
||||
se = transformPoint(x - originX, y + height - originY, rotation);
|
||||
|
||||
float top = MIN(nw.y, MIN(ne.y, MIN(sw.y, se.y)));
|
||||
float bottom = MAX(nw.y, MAX(ne.y, MAX(sw.y, se.y)));
|
||||
float left = MIN(nw.x, MIN(ne.x, MIN(sw.x, se.x)));
|
||||
float right = MAX(nw.x, MAX(ne.x, MAX(sw.x, se.x)));
|
||||
|
||||
Common::Rect res;
|
||||
res.top = (int32)(floor(top)) + originY;
|
||||
res.bottom = (int32)(ceil(bottom)) + originY;
|
||||
res.left = (int32)(floor(left)) + originX;
|
||||
res.right = (int32)(ceil(right)) + originX;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
52
graphics/tinygl/zblit.h
Normal file
52
graphics/tinygl/zblit.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_ZBLIT_H_
|
||||
#define GRAPHICS_TINYGL_ZBLIT_H_
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/tinygl/zblit_public.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
struct BlitImage;
|
||||
|
||||
namespace Internal {
|
||||
/**
|
||||
@brief Performs a cleanup of disposed blit images.
|
||||
*/
|
||||
void tglCleanupImages(); // This function checks if any blit image is to be cleaned up and deletes it.
|
||||
|
||||
// Documentation for those is the same as the one before, only those function are the one that actually execute the correct code path.
|
||||
void tglBlit(BlitImage *blitImage, const BlitTransform &transform);
|
||||
|
||||
// Disables blending, transforms and tinting.
|
||||
void tglBlitFast(BlitImage *blitImage, int x, int y);
|
||||
|
||||
void tglBlitZBuffer(BlitImage *blitImage, int x, int y);
|
||||
|
||||
} // end of namespace Internal
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif // GRAPHICS_TINYGL_ZBLIT_H_
|
||||
157
graphics/tinygl/zblit_public.h
Normal file
157
graphics/tinygl/zblit_public.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_ZBLIT_PUBLIC_H
|
||||
#define GRAPHICS_TINYGL_ZBLIT_PUBLIC_H
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
struct BlitTransform {
|
||||
BlitTransform(int dstX, int dstY) : _rotation(0), _originX(0), _originY(0), _aTint(1.0f),
|
||||
_rTint(1.0f), _gTint(1.0f), _bTint(1.0), _flipHorizontally(false),
|
||||
_flipVertically(false) {
|
||||
_destinationRectangle.translate(dstX, dstY);
|
||||
}
|
||||
|
||||
void sourceRectangle(int srcX, int srcY, int srcWidth, int srcHeight) {
|
||||
_sourceRectangle.left = srcX;
|
||||
_sourceRectangle.top = srcY;
|
||||
_sourceRectangle.setWidth(srcWidth);
|
||||
_sourceRectangle.setHeight(srcHeight);
|
||||
}
|
||||
|
||||
void tint(float aTint, float rTint = 1.0f, float gTint = 1.0f, float bTint = 1.0f) {
|
||||
_aTint = aTint;
|
||||
_rTint = rTint;
|
||||
_gTint = gTint;
|
||||
_bTint = bTint;
|
||||
}
|
||||
|
||||
void scale(int width, int height) {
|
||||
_destinationRectangle.setWidth(width);
|
||||
_destinationRectangle.setHeight(height);
|
||||
}
|
||||
|
||||
void rotate(int rotation, int originX, int originY) {
|
||||
_rotation = rotation;
|
||||
_originX = originX;
|
||||
_originY = originY;
|
||||
}
|
||||
|
||||
void flip(bool verticalFlip, bool horizontalFlip) {
|
||||
_flipVertically = verticalFlip;
|
||||
_flipHorizontally = horizontalFlip;
|
||||
}
|
||||
|
||||
bool operator==(const BlitTransform &other) const {
|
||||
return
|
||||
_sourceRectangle == other._sourceRectangle && _destinationRectangle == other._destinationRectangle &&
|
||||
_rotation == other._rotation && _originX == other._originX && _originY == other._originY &&
|
||||
_aTint == other._aTint && _rTint == other._rTint && _gTint == other._gTint && _bTint == other._bTint &&
|
||||
_flipHorizontally == other._flipHorizontally && _flipVertically == other._flipVertically;
|
||||
}
|
||||
|
||||
Common::Rect _sourceRectangle;
|
||||
Common::Rect _destinationRectangle;
|
||||
int _rotation;
|
||||
int _originX, _originY;
|
||||
float _aTint, _rTint, _gTint, _bTint;
|
||||
bool _flipHorizontally, _flipVertically;
|
||||
};
|
||||
|
||||
struct BlitImage;
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
/**
|
||||
@brief Generates a new blit image.
|
||||
@return returns an opaque pointer to the blit image.
|
||||
*/
|
||||
TinyGL::BlitImage *tglGenBlitImage();
|
||||
|
||||
/**
|
||||
@brief Copies a surface data into the provided blit image.
|
||||
@param pointer to the blit image.
|
||||
@param reference to the surface that's being copied
|
||||
@param color key value for alpha color keying
|
||||
@param boolean that enables alpha color keying
|
||||
*/
|
||||
void tglUploadBlitImage(TinyGL::BlitImage *blitImage, const Graphics::Surface &surface, uint32 colorKey, bool applyColorKey, bool zBuffer = false);
|
||||
|
||||
/**
|
||||
@brief Destroys an instance of blit image.
|
||||
@param pointer to the blit image.
|
||||
*/
|
||||
void tglDeleteBlitImage(TinyGL::BlitImage *blitImage);
|
||||
|
||||
/**
|
||||
@brief Getter for current blit image width and height
|
||||
@param pointer to the blit image.
|
||||
@param reference to the width variable
|
||||
@param reference to the height variable
|
||||
*/
|
||||
void tglGetBlitImageSize(TinyGL::BlitImage *blitImage, int &width, int &height);
|
||||
|
||||
/**
|
||||
@brief Provides a way to check if the image has been updated.
|
||||
@param pointer to the blit image.
|
||||
@param boolean that enables alpha color keying
|
||||
*/
|
||||
int tglGetBlitImageVersion(TinyGL::BlitImage *blitImage);
|
||||
|
||||
/**
|
||||
@brief Blits an image to the color buffer.
|
||||
@param pointer to the blit image.
|
||||
@param blit transform information.
|
||||
*/
|
||||
void tglBlit(TinyGL::BlitImage *blitImage, const TinyGL::BlitTransform &transform);
|
||||
|
||||
/**
|
||||
@brief Blits an image to the color buffer.
|
||||
@param pointer to the blit image.
|
||||
@param x destination coordinate.
|
||||
@param y destination coordinate.
|
||||
*/
|
||||
void tglBlit(TinyGL::BlitImage *blitImage, int x, int y);
|
||||
|
||||
/**
|
||||
@brief Blits an image to the color buffer without performinc any type of blending, image transformation or tinting.
|
||||
@param pointer to the blit image.
|
||||
@param x destination coordinate.
|
||||
@param y destination coordinate.
|
||||
*/
|
||||
void tglBlitFast(TinyGL::BlitImage *blitImage, int x, int y);
|
||||
|
||||
/**
|
||||
@brief Blits an image to the depth buffer.
|
||||
@param pointer to the blit image.
|
||||
@param x destination coordinate.
|
||||
@param y destination coordinate.
|
||||
*/
|
||||
void tglBlitZBuffer(TinyGL::BlitImage *blitImage, int x, int y);
|
||||
|
||||
void tglIncBlitImageRef(TinyGL::BlitImage *blitImage);
|
||||
|
||||
#endif // GRAPHICS_TINYGL_ZBLIT_PUBLIC_H
|
||||
487
graphics/tinygl/zbuffer.cpp
Normal file
487
graphics/tinygl/zbuffer.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
// Z buffer: 16,32 bits Z / 16 bits color
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memory.h"
|
||||
|
||||
#include "graphics/tinygl/zbuffer.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
FrameBuffer::FrameBuffer(int width, int height, const Graphics::PixelFormat &format, bool enableStencilBuffer) {
|
||||
_pbufWidth = width;
|
||||
_pbufHeight = height;
|
||||
_pbufFormat = format;
|
||||
_pbufBpp = _pbufFormat.bytesPerPixel;
|
||||
_pbufPitch = (_pbufWidth * _pbufBpp + 3) & ~3;
|
||||
|
||||
_pbuf = (byte *)gl_zalloc(_pbufHeight * _pbufPitch * sizeof(byte));
|
||||
_zbuf = (uint *)gl_zalloc(_pbufWidth * _pbufHeight * sizeof(uint));
|
||||
if (enableStencilBuffer)
|
||||
_sbuf = (byte *)gl_zalloc(_pbufWidth * _pbufHeight * sizeof(byte));
|
||||
else
|
||||
_sbuf = nullptr;
|
||||
|
||||
_offscreenBuffer.pbuf = _pbuf;
|
||||
_offscreenBuffer.zbuf = _zbuf;
|
||||
|
||||
_currentTexture = nullptr;
|
||||
|
||||
_clippingEnabled = false;
|
||||
}
|
||||
|
||||
FrameBuffer::~FrameBuffer() {
|
||||
gl_free(_pbuf);
|
||||
gl_free(_zbuf);
|
||||
if (_sbuf)
|
||||
gl_free(_sbuf);
|
||||
}
|
||||
|
||||
Buffer *FrameBuffer::genOffscreenBuffer() {
|
||||
Buffer *buf = (Buffer *)gl_malloc(sizeof(Buffer));
|
||||
buf->pbuf = (byte *)gl_zalloc(_pbufHeight * _pbufPitch);
|
||||
buf->zbuf = (uint *)gl_zalloc(_pbufWidth * _pbufHeight * sizeof(uint));
|
||||
return buf;
|
||||
}
|
||||
|
||||
void FrameBuffer::delOffscreenBuffer(Buffer *buf) {
|
||||
gl_free(buf->pbuf);
|
||||
gl_free(buf->zbuf);
|
||||
gl_free(buf);
|
||||
}
|
||||
|
||||
void FrameBuffer::clear(int clearZ, int z, int clearColor, int r, int g, int b,
|
||||
bool clearStencil, int stencilValue) {
|
||||
if (_clippingEnabled) {
|
||||
clearRegion(_clipRectangle.left, _clipRectangle.top,
|
||||
_clipRectangle.width(), _clipRectangle.height(),
|
||||
clearZ, z, clearColor, r, g, b, clearStencil, stencilValue);
|
||||
return;
|
||||
}
|
||||
if (clearZ) {
|
||||
const uint8 *zc = (const uint8 *)&z;
|
||||
uint i;
|
||||
for (i = 1; i < sizeof(z) && zc[0] == zc[i]; i++) { ; }
|
||||
if (i == sizeof(z)) {
|
||||
// All "z" bytes are identical, use memset (fast)
|
||||
memset(_zbuf, zc[0], sizeof(uint) * _pbufWidth * _pbufHeight);
|
||||
} else {
|
||||
// Cannot use memset, use a variant working on integers (possibly slower)
|
||||
Common::memset32((uint32 *)_zbuf, z, _pbufWidth * _pbufHeight);
|
||||
}
|
||||
}
|
||||
if (clearColor) {
|
||||
byte *pp = _pbuf;
|
||||
uint32 color = _pbufFormat.RGBToColor(r, g, b);
|
||||
const uint8 *colorc = (uint8 *)&color;
|
||||
uint i;
|
||||
for (i = 1; i < sizeof(color) && colorc[0] == colorc[i]; i++) { ; }
|
||||
if (i == sizeof(color)) {
|
||||
// All "color" bytes are identical, use memset (fast)
|
||||
memset(pp, colorc[0], _pbufPitch * _pbufHeight);
|
||||
} else {
|
||||
// Cannot use memset, use a variant working on shorts/ints (possibly slower)
|
||||
switch(_pbufBpp) {
|
||||
case 2:
|
||||
Common::memset16((uint16 *)pp, color, _pbufWidth * _pbufHeight);
|
||||
break;
|
||||
case 4:
|
||||
Common::memset32((uint32 *)pp, color, _pbufWidth * _pbufHeight);
|
||||
break;
|
||||
default:
|
||||
error("Unsupported pixel size %i", _pbufBpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_sbuf && clearStencil) {
|
||||
memset(_sbuf, stencilValue, _pbufWidth * _pbufHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuffer::clearRegion(int x, int y, int w, int h, bool clearZ, int z,
|
||||
bool clearColor, int r, int g, int b, bool clearStencil, int stencilValue) {
|
||||
if (clearZ) {
|
||||
int height = h;
|
||||
uint *zbuf = _zbuf + (y * _pbufWidth) + x;
|
||||
const uint8 *zc = (const uint8 *)&z;
|
||||
uint i;
|
||||
for (i = 1; i < sizeof(z) && zc[0] == zc[i]; i++) { ; }
|
||||
if (i == sizeof(z)) {
|
||||
// All "z" bytes are identical, use memset (fast)
|
||||
while (height--) {
|
||||
memset(zbuf, zc[0], sizeof(*zbuf) * w);
|
||||
zbuf += _pbufWidth;
|
||||
}
|
||||
} else {
|
||||
// Cannot use memset, use a variant working on integers (possibly slower)
|
||||
while (height--) {
|
||||
Common::memset32((uint32 *)zbuf, z, w);
|
||||
zbuf += _pbufWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clearColor) {
|
||||
int height = h;
|
||||
byte *pp = _pbuf + y * _pbufPitch + x * _pbufBpp;
|
||||
uint32 color = _pbufFormat.RGBToColor(r, g, b);
|
||||
const uint8 *colorc = (uint8 *)&color;
|
||||
uint i;
|
||||
for (i = 1; i < sizeof(color) && colorc[0] == colorc[i]; i++) { ; }
|
||||
if (i == sizeof(color)) {
|
||||
// All "color" bytes are identical, use memset (fast)
|
||||
while (height--) {
|
||||
memset(pp, colorc[0], _pbufBpp * w);
|
||||
pp += _pbufPitch;
|
||||
}
|
||||
} else {
|
||||
// Cannot use memset, use a variant working on shorts/ints (possibly slower)
|
||||
while (height--) {
|
||||
switch(_pbufBpp) {
|
||||
case 2:
|
||||
Common::memset16((uint16 *)pp, color, w);
|
||||
break;
|
||||
case 4:
|
||||
Common::memset32((uint32 *)pp, color, w);
|
||||
break;
|
||||
default:
|
||||
error("Unsupported pixel size %i", _pbufBpp);
|
||||
}
|
||||
pp += _pbufPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_sbuf && clearStencil) {
|
||||
byte *pp = _sbuf + y * _pbufWidth + x;
|
||||
for (int i = y; i < y + h; i++) {
|
||||
memset(pp, stencilValue, w);
|
||||
pp += _pbufWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline static void blitPixel(uint8 offset, uint *from_z, uint *to_z, uint z_length, byte *from_color, byte *to_color, uint color_length) {
|
||||
const uint d = from_z[offset];
|
||||
if (d > to_z[offset]) {
|
||||
memcpy(to_color + offset, from_color + offset, color_length);
|
||||
memcpy(to_z + offset, &d, z_length);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuffer::blitOffscreenBuffer(Buffer *buf) {
|
||||
// TODO: could be faster, probably.
|
||||
#define UNROLL_COUNT 16
|
||||
if (buf->used) {
|
||||
const int pixel_bytes = _pbufBpp;
|
||||
const int unrolled_pixel_bytes = pixel_bytes * UNROLL_COUNT;
|
||||
byte *to = _pbuf;
|
||||
byte *from = buf->pbuf;
|
||||
uint *to_z = _zbuf;
|
||||
uint *from_z = buf->zbuf;
|
||||
int count = _pbufWidth * _pbufHeight;
|
||||
while (count >= UNROLL_COUNT) {
|
||||
blitPixel(0x0, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x1, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x2, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x3, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x4, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x5, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x6, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x7, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x8, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0x9, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xA, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xB, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xC, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xD, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xE, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
blitPixel(0xF, from_z, to_z, sizeof(int), from, to, pixel_bytes);
|
||||
count -= UNROLL_COUNT;
|
||||
to += unrolled_pixel_bytes;
|
||||
from += unrolled_pixel_bytes;
|
||||
to_z += UNROLL_COUNT;
|
||||
}
|
||||
switch (count) {
|
||||
case 0xF: blitPixel(0xE, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0xE: blitPixel(0xD, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0xD: blitPixel(0xC, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0xC: blitPixel(0xB, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0xB: blitPixel(0xA, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0xA: blitPixel(0x9, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x9: blitPixel(0x8, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x8: blitPixel(0x7, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x7: blitPixel(0x6, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x6: blitPixel(0x5, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x5: blitPixel(0x4, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x4: blitPixel(0x3, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x3: blitPixel(0x2, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x2: blitPixel(0x1, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x1: blitPixel(0x0, from_z, to_z, sizeof(int), from, to, pixel_bytes); // fall through
|
||||
case 0x0: break;
|
||||
}
|
||||
}
|
||||
#undef UNROLL_COUNT
|
||||
}
|
||||
|
||||
void FrameBuffer::selectOffscreenBuffer(Buffer *buf) {
|
||||
if (buf) {
|
||||
_pbuf = buf->pbuf;
|
||||
_zbuf = buf->zbuf;
|
||||
buf->used = true;
|
||||
} else {
|
||||
_pbuf = _offscreenBuffer.pbuf;
|
||||
_zbuf = _offscreenBuffer.zbuf;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuffer::clearOffscreenBuffer(Buffer *buf) {
|
||||
memset(buf->pbuf, 0, _pbufHeight * _pbufPitch);
|
||||
memset(buf->zbuf, 0, _pbufHeight * _pbufWidth * sizeof(uint));
|
||||
buf->used = false;
|
||||
}
|
||||
|
||||
void getSurfaceRef(Graphics::Surface &surface) {
|
||||
GLContext *c = gl_get_context();
|
||||
assert(c->fb);
|
||||
c->fb->getSurfaceRef(surface);
|
||||
}
|
||||
|
||||
Graphics::Surface *copyFromFrameBuffer(const Graphics::PixelFormat &dstFormat) {
|
||||
GLContext *c = gl_get_context();
|
||||
assert(c->fb);
|
||||
return c->fb->copyFromFrameBuffer(dstFormat);
|
||||
}
|
||||
|
||||
static byte satAdd(byte a, byte b) {
|
||||
// from: https://web.archive.org/web/20190213215419/https://locklessinc.com/articles/sat_arithmetic/
|
||||
byte r = a + b;
|
||||
return (byte)(r | -(r < a));
|
||||
}
|
||||
|
||||
static byte sat16_to_8(uint32 x) {
|
||||
x = (x + 128) >> 8; // rounding 16 to 8
|
||||
return (byte)(x | -!!(x >> 8)); // branchfree saturation
|
||||
}
|
||||
|
||||
static byte fpMul(byte a, byte b) {
|
||||
// from: https://community.khronos.org/t/precision-curiosity-1-255-or-1-256/40539/11
|
||||
// correct would be (a*b)/255 but that is slow, instead we use (a*b) * 257/256 / 256
|
||||
// this also implicitly saturates
|
||||
uint32 r = a * b;
|
||||
return (byte)((r + (r >> 8) + 127) >> 8);
|
||||
}
|
||||
|
||||
void FrameBuffer::applyTextureEnvironment(
|
||||
int internalformat,
|
||||
uint previousA, uint previousR, uint previousG, uint previousB,
|
||||
byte &texA, byte &texR, byte &texG, byte &texB)
|
||||
{
|
||||
// summary notation is used from https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml
|
||||
// previousARGB is still in 16bit fixed-point format
|
||||
// texARGB is both input and output
|
||||
// GL_RGB/GL_RGBA might be identical as TexelBuffer returns As=1
|
||||
|
||||
struct Arg {
|
||||
byte a, r, g, b;
|
||||
};
|
||||
const auto getCombineArg = [&](const GLTextureEnvArgument &mode) -> Arg {
|
||||
Arg op = {}, opColor = {};
|
||||
|
||||
// Source values
|
||||
switch (mode.sourceRGB) {
|
||||
case TGL_TEXTURE:
|
||||
opColor.a = texA;
|
||||
opColor.r = texR;
|
||||
opColor.g = texG;
|
||||
opColor.b = texB;
|
||||
break;
|
||||
case TGL_PRIMARY_COLOR:
|
||||
opColor.a = sat16_to_8(previousA);
|
||||
opColor.r = sat16_to_8(previousR);
|
||||
opColor.g = sat16_to_8(previousG);
|
||||
opColor.b = sat16_to_8(previousB);
|
||||
break;
|
||||
case TGL_CONSTANT:
|
||||
opColor.a = _textureEnv->constA;
|
||||
opColor.r = _textureEnv->constR;
|
||||
opColor.g = _textureEnv->constG;
|
||||
opColor.b = _textureEnv->constB;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment arg color source");
|
||||
break;
|
||||
}
|
||||
switch (mode.sourceAlpha) {
|
||||
case TGL_TEXTURE:
|
||||
op.a = texA;
|
||||
break;
|
||||
case TGL_PRIMARY_COLOR:
|
||||
op.a = sat16_to_8(previousA);
|
||||
break;
|
||||
case TGL_CONSTANT:
|
||||
op.a = _textureEnv->constA;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment arg alpha source");
|
||||
break;
|
||||
}
|
||||
|
||||
// Operands
|
||||
switch (mode.operandRGB) {
|
||||
case TGL_SRC_COLOR:
|
||||
op.r = opColor.r; // intermediate values were necessary for operandRGB == TGL_SRC_ALPHA
|
||||
op.g = opColor.g;
|
||||
op.b = opColor.b;
|
||||
break;
|
||||
case TGL_ONE_MINUS_SRC_COLOR:
|
||||
op.r = 255 - opColor.r;
|
||||
op.g = 255 - opColor.g;
|
||||
op.b = 255 - opColor.b;
|
||||
break;
|
||||
case TGL_SRC_ALPHA:
|
||||
op.r = op.g = op.b = opColor.a;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment arg color operand");
|
||||
break;
|
||||
}
|
||||
switch (mode.operandAlpha) {
|
||||
case TGL_SRC_ALPHA:
|
||||
break;
|
||||
case TGL_ONE_MINUS_SRC_ALPHA:
|
||||
op.a = 255 - op.a;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment arg alpha operand");
|
||||
break;
|
||||
}
|
||||
|
||||
return op;
|
||||
};
|
||||
|
||||
switch (_textureEnv->envMode) {
|
||||
case TGL_REPLACE:
|
||||
// GL_RGB: Cs | Ap
|
||||
// GL_RGBA: Cs | As
|
||||
texA = internalformat == TGL_RGBA ? texA : sat16_to_8(previousA);
|
||||
break;
|
||||
case TGL_MODULATE:
|
||||
{
|
||||
// GL_RGB: CpCs | Ap
|
||||
// GL_RGBA: CpCs | ApAs
|
||||
applyModulation(previousA, previousR, previousG, previousB, texA, texR, texG, texB);
|
||||
break;
|
||||
}
|
||||
case TGL_DECAL:
|
||||
{
|
||||
// GL_RGB: Cs | Ap
|
||||
// GL_RGBA: Cp(1-As) + CsAs | Ap
|
||||
texR = satAdd(fpMul(sat16_to_8(previousR), 255 - texA), fpMul(texR, texA));
|
||||
texG = satAdd(fpMul(sat16_to_8(previousG), 255 - texA), fpMul(texG, texA));
|
||||
texB = satAdd(fpMul(sat16_to_8(previousB), 255 - texA), fpMul(texB, texA));
|
||||
texA = sat16_to_8(previousA);
|
||||
break;
|
||||
}
|
||||
case TGL_ADD:
|
||||
{
|
||||
// GL_RGB: Cp + Cs | Ap
|
||||
// GL_RGBA: Cp + Cs | ApAs
|
||||
texA = fpMul(sat16_to_8(previousA), texA);
|
||||
texR = satAdd(sat16_to_8(previousR), texR);
|
||||
texG = satAdd(sat16_to_8(previousG), texG);
|
||||
texB = satAdd(sat16_to_8(previousB), texB);
|
||||
break;
|
||||
}
|
||||
case TGL_BLEND:
|
||||
{
|
||||
// GL_RGB: Cp(1-Cs) + CcCs | Ap
|
||||
// GL_RGBA: Cp(1-Cs) + CcCs | ApAs
|
||||
texA = fpMul(sat16_to_8(previousA), texA);
|
||||
texR = satAdd(fpMul(sat16_to_8(previousR), 255 - texR), fpMul(_textureEnv->constR, texR));
|
||||
texG = satAdd(fpMul(sat16_to_8(previousG), 255 - texG), fpMul(_textureEnv->constG, texG));
|
||||
texB = satAdd(fpMul(sat16_to_8(previousB), 255 - texB), fpMul(_textureEnv->constB, texB));
|
||||
break;
|
||||
}
|
||||
case TGL_COMBINE:
|
||||
{
|
||||
Arg arg0 = getCombineArg(_textureEnv->arg0);
|
||||
Arg arg1 = getCombineArg(_textureEnv->arg1);
|
||||
switch (_textureEnv->combineRGB) {
|
||||
case TGL_REPLACE:
|
||||
texR = arg0.r;
|
||||
texG = arg0.g;
|
||||
texB = arg0.b;
|
||||
break;
|
||||
case TGL_MODULATE:
|
||||
texR = fpMul(arg0.r, arg1.r);
|
||||
texG = fpMul(arg0.g, arg1.g);
|
||||
texB = fpMul(arg0.b, arg1.b);
|
||||
break;
|
||||
case TGL_ADD:
|
||||
texR = satAdd(arg0.r, arg1.r);
|
||||
texG = satAdd(arg0.g, arg1.g);
|
||||
texB = satAdd(arg0.b, arg1.b);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment color combine");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_textureEnv->combineAlpha) {
|
||||
case TGL_REPLACE:
|
||||
texA = arg0.a;
|
||||
break;
|
||||
case TGL_MODULATE:
|
||||
texA = fpMul(arg0.a, arg1.a);
|
||||
break;
|
||||
case TGL_ADD:
|
||||
texA = satAdd(arg0.a, arg1.a);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid texture environment alpha combine");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false && "Invalid texture environment mode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuffer::applyModulation(
|
||||
uint previousA, uint previousR, uint previousG, uint previousB,
|
||||
byte &texA, byte &texR, byte &texG, byte &texB) {
|
||||
texA = fpMul(sat16_to_8(previousA), texA);
|
||||
texR = fpMul(sat16_to_8(previousR), texR);
|
||||
texG = fpMul(sat16_to_8(previousG), texG);
|
||||
texB = fpMul(sat16_to_8(previousB), texB);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
870
graphics/tinygl/zbuffer.h
Normal file
870
graphics/tinygl/zbuffer.h
Normal file
@@ -0,0 +1,870 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_ZBUFFER_H_
|
||||
#define GRAPHICS_TINYGL_ZBUFFER_H_
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/tinygl/texelbuffer.h"
|
||||
#include "graphics/tinygl/gl.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
// Z buffer
|
||||
|
||||
#define ZB_Z_BITS 16
|
||||
|
||||
#define ZB_FOG_BITS 16
|
||||
#define ZB_FOG_MAX ( (1 << ZB_FOG_BITS) - 1 )
|
||||
|
||||
#define ZB_POINT_Z_FRAC_BITS 14
|
||||
|
||||
#define ZB_POINT_ST_FRAC_BITS 14
|
||||
#define ZB_POINT_ST_FRAC_SHIFT (ZB_POINT_ST_FRAC_BITS - 1)
|
||||
#define ZB_POINT_ST_MAX ( (_textureSize << ZB_POINT_ST_FRAC_BITS) - 1 )
|
||||
|
||||
#define ZB_POINT_RED_BITS 16
|
||||
#define ZB_POINT_RED_FRAC_BITS 8
|
||||
#define ZB_POINT_RED_FRAC_SHIFT (ZB_POINT_RED_FRAC_BITS - 1)
|
||||
#define ZB_POINT_RED_MAX ( (1 << ZB_POINT_RED_BITS) - 1 )
|
||||
|
||||
#define ZB_POINT_GREEN_BITS 16
|
||||
#define ZB_POINT_GREEN_FRAC_BITS 8
|
||||
#define ZB_POINT_GREEN_FRAC_SHIFT (ZB_POINT_GREEN_FRAC_BITS - 1)
|
||||
#define ZB_POINT_GREEN_MAX ( (1 << ZB_POINT_GREEN_BITS) - 1 )
|
||||
|
||||
#define ZB_POINT_BLUE_BITS 16
|
||||
#define ZB_POINT_BLUE_FRAC_BITS 8
|
||||
#define ZB_POINT_BLUE_FRAC_SHIFT (ZB_POINT_BLUE_FRAC_BITS - 1)
|
||||
#define ZB_POINT_BLUE_MAX ( (1 << ZB_POINT_BLUE_BITS) - 1 )
|
||||
|
||||
#define ZB_POINT_ALPHA_BITS 16
|
||||
#define ZB_POINT_ALPHA_FRAC_BITS 8
|
||||
#define ZB_POINT_ALPHA_FRAC_SHIFT (ZB_POINT_ALPHA_FRAC_BITS - 1)
|
||||
#define ZB_POINT_ALPHA_MAX ( (1 << ZB_POINT_ALPHA_BITS) - 1 )
|
||||
|
||||
#define RGB_TO_PIXEL(r, g, b) _pbufFormat.ARGBToColor(255, r, g, b) // Default to 255 alpha aka solid colour.
|
||||
|
||||
static const int DRAW_DEPTH_ONLY = 0;
|
||||
static const int DRAW_FLAT = 1;
|
||||
static const int DRAW_SMOOTH = 2;
|
||||
|
||||
struct GLTextureEnv; // defined in zdirtyrect.h
|
||||
|
||||
struct Buffer {
|
||||
byte *pbuf;
|
||||
uint *zbuf;
|
||||
bool used;
|
||||
};
|
||||
|
||||
struct ZBufferPoint {
|
||||
int x, y, z; // integer coordinates in the zbuffer
|
||||
int s, t; // coordinates for the mapping
|
||||
int r, g, b, a; // color indexes
|
||||
float sz, tz; // temporary coordinates for mapping
|
||||
int f; // fog factor
|
||||
|
||||
bool operator==(const ZBufferPoint &other) const {
|
||||
return
|
||||
x == other.x &&
|
||||
y == other.y &&
|
||||
z == other.z &&
|
||||
s == other.s &&
|
||||
t == other.t &&
|
||||
r == other.r &&
|
||||
g == other.g &&
|
||||
b == other.b &&
|
||||
a == other.a;
|
||||
}
|
||||
};
|
||||
|
||||
struct FrameBuffer {
|
||||
FrameBuffer(int width, int height, const Graphics::PixelFormat &format, bool enableStencilBuffer);
|
||||
~FrameBuffer();
|
||||
|
||||
Graphics::PixelFormat getPixelFormat() {
|
||||
return _pbufFormat;
|
||||
}
|
||||
|
||||
byte *getPixelBuffer() {
|
||||
return _pbuf;
|
||||
}
|
||||
|
||||
int getPixelBufferWidth() {
|
||||
return _pbufWidth;
|
||||
}
|
||||
|
||||
int getPixelBufferHeight() {
|
||||
return _pbufHeight;
|
||||
}
|
||||
|
||||
int getPixelBufferPitch() {
|
||||
return _pbufPitch;
|
||||
}
|
||||
|
||||
int getPixelBufferBpp() {
|
||||
return _pbufBpp;
|
||||
}
|
||||
|
||||
const uint *getZBuffer() {
|
||||
return _zbuf;
|
||||
}
|
||||
|
||||
Graphics::Surface *copyFromFrameBuffer(const Graphics::PixelFormat &dstFormat) {
|
||||
Graphics::Surface tmp;
|
||||
tmp.init(_pbufWidth, _pbufHeight, _pbufPitch, _pbuf, _pbufFormat);
|
||||
return tmp.convertTo(dstFormat);
|
||||
}
|
||||
|
||||
void getSurfaceRef(Graphics::Surface &surface) {
|
||||
surface.init(_pbufWidth, _pbufHeight, _pbufPitch, _pbuf, _pbufFormat);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
FORCEINLINE void setPixelAt(int pixel, uint32 value) {
|
||||
switch (_pbufBpp) {
|
||||
case 2:
|
||||
((uint16 *) _pbuf)[pixel] = value;
|
||||
return;
|
||||
case 3:
|
||||
pixel *= 3;
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
_pbuf[pixel + 0] = (value >> 16) & 0xFF;
|
||||
_pbuf[pixel + 1] = (value >> 8) & 0xFF;
|
||||
_pbuf[pixel + 2] = value & 0xFF;
|
||||
#elif defined(SCUMM_LITTLE_ENDIAN)
|
||||
_pbuf[pixel + 0] = value & 0xFF;
|
||||
_pbuf[pixel + 1] = (value >> 8) & 0xFF;
|
||||
_pbuf[pixel + 2] = (value >> 16) & 0xFF;
|
||||
#endif
|
||||
return;
|
||||
case 4:
|
||||
((uint32 *) _pbuf)[pixel] = value;
|
||||
return;
|
||||
}
|
||||
error("setPixelAt: Unhandled bytesPerPixel %d", int(_pbufBpp));
|
||||
}
|
||||
|
||||
FORCEINLINE uint32 getPixelAt(int i) const {
|
||||
switch (_pbufBpp) {
|
||||
case 2:
|
||||
return ((uint16 *) _pbuf)[i];
|
||||
case 3:
|
||||
i *= 3;
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
return (_pbuf[i + 0] << 16) | (_pbuf[i + 1] << 8) | _pbuf[i + 2];
|
||||
#elif defined(SCUMM_LITTLE_ENDIAN)
|
||||
return _pbuf[i + 0] | (_pbuf[i + 1] << 8) | (_pbuf[i + 2] << 16);
|
||||
#endif
|
||||
case 4:
|
||||
return ((uint32 *) _pbuf)[i];
|
||||
}
|
||||
error("getPixelAt: Unhandled bytesPerPixel %d", int(_pbufBpp));
|
||||
}
|
||||
|
||||
FORCEINLINE bool compareDepth(uint &zSrc, uint &zDst) {
|
||||
if (!_depthTestEnabled)
|
||||
return true;
|
||||
|
||||
switch (_depthFunc) {
|
||||
case TGL_NEVER:
|
||||
break;
|
||||
case TGL_LESS:
|
||||
if (zDst < zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_EQUAL:
|
||||
if (zDst == zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_LEQUAL:
|
||||
if (zDst <= zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_GREATER:
|
||||
if (zDst > zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_NOTEQUAL:
|
||||
if (zDst != zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_GEQUAL:
|
||||
if (zDst >= zSrc)
|
||||
return true;
|
||||
break;
|
||||
case TGL_ALWAYS:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool checkAlphaTest(byte aSrc) {
|
||||
if (!_alphaTestEnabled)
|
||||
return true;
|
||||
|
||||
switch (_alphaTestFunc) {
|
||||
case TGL_NEVER:
|
||||
break;
|
||||
case TGL_LESS:
|
||||
if (aSrc < _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_EQUAL:
|
||||
if (aSrc == _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_LEQUAL:
|
||||
if (aSrc <= _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_GREATER:
|
||||
if (aSrc > _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_NOTEQUAL:
|
||||
if (aSrc != _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_GEQUAL:
|
||||
if (aSrc >= _alphaTestRefVal)
|
||||
return true;
|
||||
break;
|
||||
case TGL_ALWAYS:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE bool stencilTest(byte sSrc) {
|
||||
switch (_stencilTestFunc) {
|
||||
case TGL_NEVER:
|
||||
break;
|
||||
case TGL_LESS:
|
||||
if ((_stencilRefVal & _stencilMask) < (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_LEQUAL:
|
||||
if ((_stencilRefVal & _stencilMask) <= (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_GREATER:
|
||||
if ((_stencilRefVal & _stencilMask) > (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_GEQUAL:
|
||||
if ((_stencilRefVal & _stencilMask) >= (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_EQUAL:
|
||||
if ((_stencilRefVal & _stencilMask) == (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_NOTEQUAL:
|
||||
if ((_stencilRefVal & _stencilMask) != (sSrc & _stencilMask))
|
||||
return true;
|
||||
break;
|
||||
case TGL_ALWAYS:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FORCEINLINE void stencilOp(bool stencilTestResult, bool depthTestResult, byte *sDst) {
|
||||
int op = !stencilTestResult ? _stencilSfail : !depthTestResult ? _stencilDpfail : _stencilDppass;
|
||||
byte oldValue = *sDst;
|
||||
byte newValue = oldValue;
|
||||
switch (op) {
|
||||
case TGL_KEEP:
|
||||
return;
|
||||
case TGL_ZERO:
|
||||
newValue = 0;
|
||||
break;
|
||||
case TGL_REPLACE:
|
||||
newValue = _stencilRefVal;
|
||||
break;
|
||||
case TGL_INCR:
|
||||
if (newValue < 255)
|
||||
newValue++;
|
||||
break;
|
||||
case TGL_INCR_WRAP:
|
||||
newValue++;
|
||||
break;
|
||||
case TGL_DECR:
|
||||
if (newValue > 0)
|
||||
newValue--;
|
||||
break;
|
||||
case TGL_DECR_WRAP:
|
||||
newValue--;
|
||||
break;
|
||||
case TGL_INVERT:
|
||||
newValue = ~newValue;
|
||||
}
|
||||
*sDst = (newValue & _stencilWriteMask) | (oldValue & ~_stencilWriteMask);
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaTest, bool kBlendingEnabled>
|
||||
FORCEINLINE void writePixel(int pixel, int value) {
|
||||
writePixel<kEnableAlphaTest, kBlendingEnabled, false>(pixel, value, 0);
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaTest, bool kBlendingEnabled, bool kDepthWrite>
|
||||
FORCEINLINE void writePixel(int pixel, int value, uint z) {
|
||||
if (kBlendingEnabled == false) {
|
||||
setPixelAt(pixel, value);
|
||||
if (kDepthWrite) {
|
||||
_zbuf[pixel] = z;
|
||||
}
|
||||
} else {
|
||||
byte rSrc, gSrc, bSrc, aSrc;
|
||||
_pbufFormat.colorToARGB(value, aSrc, rSrc, gSrc, bSrc);
|
||||
|
||||
writePixel<kEnableAlphaTest, kBlendingEnabled, kDepthWrite>(pixel, aSrc, rSrc, gSrc, bSrc, z);
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE void writePixel(int pixel, int value) {
|
||||
if (_alphaTestEnabled) {
|
||||
writePixel<true>(pixel, value);
|
||||
} else {
|
||||
writePixel<false>(pixel, value);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kDepthWrite, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void putPixelNoTexture(int fbOffset, uint *pz, byte *ps, int _a,
|
||||
int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a,
|
||||
int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
||||
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx);
|
||||
|
||||
enum class ColorMode {
|
||||
NoInterpolation,
|
||||
Default, // GL_TEXTURE_ENV_MODE == GL_MODULATE
|
||||
CustomTexEnv
|
||||
};
|
||||
|
||||
template <bool kDepthWrite, ColorMode kColorMode, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kDepthTestEnabled>
|
||||
void putPixelTexture(int fbOffset, const TexelBuffer *texture,
|
||||
uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a,
|
||||
int x, int y, uint &z, int &t, int &s,
|
||||
uint &r, uint &g, uint &b, uint &a,
|
||||
int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
||||
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx);
|
||||
|
||||
template <bool kDepthWrite, bool kEnableScissor, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void putPixelDepth(uint *pz, byte *ps, int _a, int x, int y, uint &z, int &dzdx);
|
||||
|
||||
|
||||
template <bool kEnableAlphaTest>
|
||||
FORCEINLINE void writePixel(int pixel, int value) {
|
||||
if (_blendingEnabled) {
|
||||
writePixel<kEnableAlphaTest, true>(pixel, value);
|
||||
} else {
|
||||
writePixel<kEnableAlphaTest, false>(pixel, value);
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE void writePixel(int pixel, byte rSrc, byte gSrc, byte bSrc) {
|
||||
writePixel(pixel, 255, rSrc, gSrc, bSrc);
|
||||
}
|
||||
|
||||
FORCEINLINE bool scissorPixel(int x, int y) {
|
||||
return !_clipRectangle.contains(x, y);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) {
|
||||
if (_alphaTestEnabled) {
|
||||
writePixel<true>(pixel, aSrc, rSrc, gSrc, bSrc);
|
||||
} else {
|
||||
writePixel<false>(pixel, aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <bool kEnableAlphaTest>
|
||||
FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) {
|
||||
if (_blendingEnabled) {
|
||||
writePixel<kEnableAlphaTest, true>(pixel, aSrc, rSrc, gSrc, bSrc);
|
||||
} else {
|
||||
writePixel<kEnableAlphaTest, false>(pixel, aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaTest, bool kBlendingEnabled>
|
||||
FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) {
|
||||
writePixel<kEnableAlphaTest, kBlendingEnabled, false>(pixel, aSrc, rSrc, gSrc, bSrc, 0);
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaTest, bool kBlendingEnabled, bool kDepthWrite>
|
||||
FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc, uint z) {
|
||||
writePixel<kEnableAlphaTest, kBlendingEnabled, kDepthWrite, false>(pixel, aSrc, rSrc, gSrc, bSrc, z, 0.0f, 0, 0, 0);
|
||||
}
|
||||
|
||||
template <bool kEnableAlphaTest, bool kBlendingEnabled, bool kDepthWrite, bool kFogMode>
|
||||
FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc, float z, uint fog, byte fog_r, byte fog_g, byte fog_b) {
|
||||
if (kEnableAlphaTest) {
|
||||
if (!checkAlphaTest(aSrc))
|
||||
return;
|
||||
}
|
||||
|
||||
if (kDepthWrite) {
|
||||
_zbuf[pixel] = z;
|
||||
}
|
||||
|
||||
if (kFogMode) {
|
||||
int oneMinusFog = (1 << ZB_FOG_BITS) - fog;
|
||||
int finalR = (rSrc * fog + fog_r * oneMinusFog) >> ZB_FOG_BITS;
|
||||
int finalG = (gSrc * fog + fog_g * oneMinusFog) >> ZB_FOG_BITS;
|
||||
int finalB = (bSrc * fog + fog_b * oneMinusFog) >> ZB_FOG_BITS;
|
||||
if (finalR > 255) {
|
||||
rSrc = 255;
|
||||
} else {
|
||||
rSrc = finalR;
|
||||
}
|
||||
if (finalG > 255) {
|
||||
gSrc = 255;
|
||||
} else {
|
||||
gSrc = finalG;
|
||||
}
|
||||
if (finalB > 255) {
|
||||
bSrc = 255;
|
||||
} else {
|
||||
bSrc = finalB;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kBlendingEnabled) {
|
||||
setPixelAt(pixel, _pbufFormat.ARGBToColor(aSrc, rSrc, gSrc, bSrc));
|
||||
} else {
|
||||
byte rDst, gDst, bDst, aDst;
|
||||
_pbufFormat.colorToARGB(getPixelAt(pixel), aDst, rDst, gDst, bDst);
|
||||
switch (_sourceBlendingFactor) {
|
||||
case TGL_ZERO:
|
||||
rSrc = gSrc = bSrc = 0;
|
||||
break;
|
||||
case TGL_ONE:
|
||||
break;
|
||||
case TGL_DST_COLOR:
|
||||
rSrc = (rDst * rSrc) >> 8;
|
||||
gSrc = (gDst * gSrc) >> 8;
|
||||
bSrc = (bDst * bSrc) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_DST_COLOR:
|
||||
rSrc = (rSrc * (255 - rDst)) >> 8;
|
||||
gSrc = (gSrc * (255 - gDst)) >> 8;
|
||||
bSrc = (bSrc * (255 - bDst)) >> 8;
|
||||
break;
|
||||
case TGL_SRC_ALPHA:
|
||||
rSrc = (rSrc * aSrc) >> 8;
|
||||
gSrc = (gSrc * aSrc) >> 8;
|
||||
bSrc = (bSrc * aSrc) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_SRC_ALPHA:
|
||||
rSrc = (rSrc * (255 - aSrc)) >> 8;
|
||||
gSrc = (gSrc * (255 - aSrc)) >> 8;
|
||||
bSrc = (bSrc * (255 - aSrc)) >> 8;
|
||||
break;
|
||||
case TGL_DST_ALPHA:
|
||||
rSrc = (rSrc * aDst) >> 8;
|
||||
gSrc = (gSrc * aDst) >> 8;
|
||||
bSrc = (bSrc * aDst) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_DST_ALPHA:
|
||||
rSrc = (rSrc * (255 - aDst)) >> 8;
|
||||
gSrc = (gSrc * (255 - aDst)) >> 8;
|
||||
bSrc = (bSrc * (255 - aDst)) >> 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_destinationBlendingFactor) {
|
||||
case TGL_ZERO:
|
||||
rDst = gDst = bDst = 0;
|
||||
break;
|
||||
case TGL_ONE:
|
||||
break;
|
||||
case TGL_DST_COLOR:
|
||||
rDst = (rDst * rSrc) >> 8;
|
||||
gDst = (gDst * gSrc) >> 8;
|
||||
bDst = (bDst * bSrc) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_DST_COLOR:
|
||||
rDst = (rDst * (255 - rSrc)) >> 8;
|
||||
gDst = (gDst * (255 - gSrc)) >> 8;
|
||||
bDst = (bDst * (255 - bSrc)) >> 8;
|
||||
break;
|
||||
case TGL_SRC_ALPHA:
|
||||
rDst = (rDst * aSrc) >> 8;
|
||||
gDst = (gDst * aSrc) >> 8;
|
||||
bDst = (bDst * aSrc) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_SRC_ALPHA:
|
||||
rDst = (rDst * (255 - aSrc)) >> 8;
|
||||
gDst = (gDst * (255 - aSrc)) >> 8;
|
||||
bDst = (bDst * (255 - aSrc)) >> 8;
|
||||
break;
|
||||
case TGL_DST_ALPHA:
|
||||
rDst = (rDst * aDst) >> 8;
|
||||
gDst = (gDst * aDst) >> 8;
|
||||
bDst = (bDst * aDst) >> 8;
|
||||
break;
|
||||
case TGL_ONE_MINUS_DST_ALPHA:
|
||||
rDst = (rDst * (255 - aDst)) >> 8;
|
||||
gDst = (gDst * (255 - aDst)) >> 8;
|
||||
bDst = (bDst * (255 - aDst)) >> 8;
|
||||
break;
|
||||
case TGL_SRC_ALPHA_SATURATE: {
|
||||
int factor = aSrc < 1 - aDst ? aSrc : 1 - aDst;
|
||||
rDst = (rDst * factor) >> 8;
|
||||
gDst = (gDst * factor) >> 8;
|
||||
bDst = (bDst * factor) >> 8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int finalR = rDst + rSrc;
|
||||
int finalG = gDst + gSrc;
|
||||
int finalB = bDst + bSrc;
|
||||
if (finalR > 255) {
|
||||
finalR = 255;
|
||||
}
|
||||
if (finalG > 255) {
|
||||
finalG = 255;
|
||||
}
|
||||
if (finalB > 255) {
|
||||
finalB = 255;
|
||||
}
|
||||
setPixelAt(pixel, _pbufFormat.RGBToColor(finalR, finalG, finalB));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void clear(int clear_z, int z, int clear_color, int r, int g, int b,
|
||||
bool clearStencil, int stencilValue);
|
||||
void clearRegion(int x, int y, int w, int h, bool clearZ, int z,
|
||||
bool clearColor, int r, int g, int b, bool clearStencil, int stencilValue);
|
||||
|
||||
const Common::Rect &getClippingRectangle() const {
|
||||
return _clipRectangle;
|
||||
}
|
||||
|
||||
void setupScissor(bool enable, const int (&scissor)[4], const Common::Rect *clippingRectangle) {
|
||||
_clippingEnabled = enable || clippingRectangle;
|
||||
|
||||
if (enable && clippingRectangle) {
|
||||
_clipRectangle = clippingRectangle->findIntersectingRect(Common::Rect(
|
||||
scissor[0],
|
||||
// all viewport calculations are already flipped upside down
|
||||
_pbufHeight - scissor[1] - scissor[3],
|
||||
scissor[0] + scissor[2],
|
||||
_pbufHeight - scissor[1]));
|
||||
} else if (enable) {
|
||||
_clipRectangle = Common::Rect(
|
||||
scissor[0],
|
||||
// all viewport calculations are already flipped upside down
|
||||
_pbufHeight - scissor[1] - scissor[3],
|
||||
scissor[0] + scissor[2],
|
||||
_pbufHeight - scissor[1]);
|
||||
} else if (clippingRectangle) {
|
||||
_clipRectangle = *clippingRectangle;
|
||||
} else {
|
||||
_clipRectangle = Common::Rect(0, 0, _pbufWidth, _pbufHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void enableBlending(bool enable) {
|
||||
_blendingEnabled = enable;
|
||||
}
|
||||
|
||||
void setBlendingFactors(int sFactor, int dFactor) {
|
||||
_sourceBlendingFactor = sFactor;
|
||||
_destinationBlendingFactor = dFactor;
|
||||
}
|
||||
|
||||
void enableAlphaTest(bool enable) {
|
||||
_alphaTestEnabled = enable;
|
||||
}
|
||||
|
||||
void setAlphaTestFunc(int func, int ref) {
|
||||
_alphaTestFunc = func;
|
||||
_alphaTestRefVal = ref;
|
||||
}
|
||||
|
||||
void enableDepthTest(bool enable) {
|
||||
_depthTestEnabled = enable;
|
||||
}
|
||||
|
||||
void setDepthFunc(int func) {
|
||||
_depthFunc = func;
|
||||
}
|
||||
|
||||
void enableDepthWrite(bool enable) {
|
||||
_depthWrite = enable;
|
||||
}
|
||||
|
||||
void enableStencilTest(bool enable) {
|
||||
_stencilTestEnabled = enable;
|
||||
}
|
||||
|
||||
void setStencilWriteMask(uint stencilWriteMask) {
|
||||
_stencilWriteMask = stencilWriteMask;
|
||||
}
|
||||
|
||||
void enablePolygonStipple(bool enable) {
|
||||
_polygonStippleEnabled = enable;
|
||||
}
|
||||
|
||||
void setPolygonStipplePattern(const byte *stipple) {
|
||||
_polygonStipplePattern = stipple;
|
||||
}
|
||||
|
||||
void enableTwoColorStipple(bool enable) {
|
||||
_twoColorStippleEnabled = enable;
|
||||
}
|
||||
|
||||
void setStippleColor(int r, int g, int b) {
|
||||
_stippleColor = RGB_TO_PIXEL(r, g, b);
|
||||
}
|
||||
|
||||
void setStencilTestFunc(int stencilFunc, byte stencilValue, byte stencilMask) {
|
||||
_stencilTestFunc = stencilFunc;
|
||||
_stencilRefVal = stencilValue;
|
||||
_stencilMask = stencilMask;
|
||||
}
|
||||
|
||||
void setStencilOp(int stencilSfail, int stencilDpfail, int stencilDppass) {
|
||||
_stencilSfail = stencilSfail;
|
||||
_stencilDpfail = stencilDpfail;
|
||||
_stencilDppass = stencilDppass;
|
||||
}
|
||||
|
||||
void setOffsetStates(int offsetStates) {
|
||||
_offsetStates = offsetStates;
|
||||
}
|
||||
|
||||
void setOffsetFactor(float offsetFactor) {
|
||||
_offsetFactor = offsetFactor;
|
||||
}
|
||||
|
||||
void setOffsetUnits(float offsetUnits) {
|
||||
_offsetUnits = offsetUnits;
|
||||
}
|
||||
|
||||
void setTexture(const TexelBuffer *texture, uint wraps, uint wrapt) {
|
||||
_currentTexture = texture;
|
||||
_wrapS = wraps;
|
||||
_wrapT = wrapt;
|
||||
}
|
||||
|
||||
void setTextureEnvironment(const GLTextureEnv *texEnv) {
|
||||
_textureEnv = texEnv;
|
||||
}
|
||||
|
||||
void setTextureSizeAndMask(int textureSize, int textureSizeMask) {
|
||||
_textureSize = textureSize;
|
||||
_textureSizeMask = textureSizeMask;
|
||||
}
|
||||
|
||||
void setFogEnabled(bool enable) {
|
||||
_fogEnabled = enable;
|
||||
}
|
||||
|
||||
void setFogColor(float colorR, float colorG, float colorB) {
|
||||
_fogColorR = colorR;
|
||||
_fogColorG = colorG;
|
||||
_fogColorB = colorB;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Blit the buffer to the screen buffer, checking the depth of the pixels.
|
||||
* Eack pixel is copied if and only if its depth value is bigger than the
|
||||
* depth value of the screen pixel, so if it is 'above'.
|
||||
*/
|
||||
Buffer *genOffscreenBuffer();
|
||||
void delOffscreenBuffer(Buffer *buffer);
|
||||
void blitOffscreenBuffer(Buffer *buffer);
|
||||
void selectOffscreenBuffer(Buffer *buffer);
|
||||
void clearOffscreenBuffer(Buffer *buffer);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool kAlphaTestEnabled, bool kEnableScissor,
|
||||
bool kBlendingEnabled, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool kAlphaTestEnabled, bool kEnableScissor,
|
||||
bool kBlendingEnabled, bool kStencilEnabled, bool kStippleEnabled>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool kAlphaTestEnabled, bool kEnableScissor,
|
||||
bool kBlendingEnabled, bool kStencilEnabled>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool enableAlphaTest, bool kEnableScissor, bool kBlendingEnabled>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool enableAlphaTest, bool kEnableScissor>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool enableAlphaTest>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode>
|
||||
void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite>
|
||||
void fillTriangleTextureMapping(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
public:
|
||||
|
||||
void fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillTriangleFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillTriangleSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
void plot(ZBufferPoint *p);
|
||||
void fillLine(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillLineZ(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
private:
|
||||
|
||||
void fillLineFlatZ(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillLineInterpZ(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillLineFlat(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
void fillLineInterp(ZBufferPoint *p1, ZBufferPoint *p2);
|
||||
|
||||
template <bool kDepthWrite>
|
||||
FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y, uint z);
|
||||
|
||||
template <bool kDepthWrite, bool kEnableScissor>
|
||||
FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y, uint z);
|
||||
|
||||
template <bool kEnableScissor>
|
||||
FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y);
|
||||
|
||||
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
|
||||
void drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2);
|
||||
|
||||
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite, bool kEnableScissor>
|
||||
void drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2);
|
||||
|
||||
void applyTextureEnvironment(
|
||||
int internalformat,
|
||||
uint previousA, uint previousR, uint previousG, uint previousB,
|
||||
byte &texA, byte &texR, byte &texG, byte &texB);
|
||||
|
||||
// the same as GL_TEXTURE_ENV_MODE == GL_MODULATE as fast-path for the default mode
|
||||
void applyModulation(
|
||||
uint previousA, uint previousR, uint previousG, uint previousB,
|
||||
byte &texA, byte &texR, byte &texG, byte &texB);
|
||||
|
||||
Buffer _offscreenBuffer;
|
||||
byte *_pbuf;
|
||||
int _pbufWidth;
|
||||
int _pbufHeight;
|
||||
int _pbufPitch;
|
||||
Graphics::PixelFormat _pbufFormat;
|
||||
int _pbufBpp;
|
||||
|
||||
uint *_zbuf;
|
||||
byte *_sbuf;
|
||||
|
||||
bool _enableStencil;
|
||||
int _textureSize;
|
||||
int _textureSizeMask;
|
||||
|
||||
Common::Rect _clipRectangle;
|
||||
bool _clippingEnabled;
|
||||
|
||||
const TexelBuffer *_currentTexture;
|
||||
const GLTextureEnv *_textureEnv;
|
||||
uint _wrapS, _wrapT;
|
||||
bool _blendingEnabled;
|
||||
int _sourceBlendingFactor;
|
||||
int _destinationBlendingFactor;
|
||||
bool _alphaTestEnabled;
|
||||
int _alphaTestFunc;
|
||||
int _alphaTestRefVal;
|
||||
bool _depthTestEnabled;
|
||||
bool _depthWrite;
|
||||
bool _stencilTestEnabled;
|
||||
int _stencilTestFunc;
|
||||
byte _stencilRefVal;
|
||||
byte _stencilMask;
|
||||
byte _stencilWriteMask;
|
||||
int _stencilSfail;
|
||||
int _stencilDpfail;
|
||||
int _stencilDppass;
|
||||
|
||||
bool _polygonStippleEnabled;
|
||||
bool _twoColorStippleEnabled;
|
||||
uint32 _stippleColor;
|
||||
const byte *_polygonStipplePattern;
|
||||
int _depthFunc;
|
||||
int _offsetStates;
|
||||
float _offsetFactor;
|
||||
float _offsetUnits;
|
||||
bool _fogEnabled;
|
||||
float _fogColorR;
|
||||
float _fogColorG;
|
||||
float _fogColorB;
|
||||
};
|
||||
|
||||
// memory.c
|
||||
void gl_free(void *p);
|
||||
void *gl_malloc(int size);
|
||||
void *gl_zalloc(int size);
|
||||
void *gl_realloc(void *p, int size);
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
823
graphics/tinygl/zdirtyrect.cpp
Normal file
823
graphics/tinygl/zdirtyrect.cpp
Normal file
@@ -0,0 +1,823 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
#include "graphics/tinygl/gl.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
GLTextureEnvArgument::GLTextureEnvArgument()
|
||||
: sourceRGB(TGL_TEXTURE)
|
||||
, operandRGB(TGL_SRC_COLOR)
|
||||
, sourceAlpha(TGL_TEXTURE)
|
||||
, operandAlpha(TGL_SRC_ALPHA) {}
|
||||
|
||||
GLTextureEnv::GLTextureEnv()
|
||||
: envMode(TGL_MODULATE)
|
||||
, combineRGB(TGL_REPLACE)
|
||||
, combineAlpha(TGL_REPLACE)
|
||||
, constA(255), constR(255), constG(255), constB(255) {}
|
||||
|
||||
bool GLTextureEnv::isDefault() const {
|
||||
return envMode == TGL_MODULATE;
|
||||
}
|
||||
|
||||
void GLContext::issueDrawCall(DrawCall *drawCall) {
|
||||
if (_enableDirtyRectangles && drawCall->getDirtyRegion().isEmpty())
|
||||
return;
|
||||
_drawCallsQueue.push_back(drawCall);
|
||||
}
|
||||
|
||||
void GLContext::debugDrawRectangle(Common::Rect rect, int r, int g, int b) {
|
||||
int fbWidth = fb->getPixelBufferWidth();
|
||||
|
||||
if (rect.left < 0)
|
||||
rect.left = 0;
|
||||
if (rect.right >= fbWidth)
|
||||
rect.right = fbWidth - 1;
|
||||
if (rect.top < 0)
|
||||
rect.top = 0;
|
||||
if (rect.bottom >= fb->getPixelBufferHeight())
|
||||
rect.bottom = fb->getPixelBufferHeight() - 1;
|
||||
|
||||
for (int x = rect.left; x < rect.right; x++) {
|
||||
fb->writePixel(rect.top * fbWidth + x, 255, r, g, b);
|
||||
fb->writePixel((rect.bottom - 1) * fbWidth + x, 255, r, g, b);
|
||||
}
|
||||
for (int y = rect.top; y < rect.bottom; y++) {
|
||||
fb->writePixel(y * fbWidth + rect.left, 255, r, g, b);
|
||||
fb->writePixel(y * fbWidth + rect.right - 1, 255, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
struct DirtyRectangle {
|
||||
Common::Rect rectangle;
|
||||
int r, g, b;
|
||||
|
||||
DirtyRectangle() {
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
}
|
||||
DirtyRectangle(Common::Rect rect, int red, int green, int blue) {
|
||||
rectangle = rect;
|
||||
r = red;
|
||||
g = green;
|
||||
b = blue;
|
||||
}
|
||||
};
|
||||
|
||||
void GLContext::disposeResources() {
|
||||
// Dispose textures and resources.
|
||||
bool allDisposed = true;
|
||||
do {
|
||||
allDisposed = true;
|
||||
for (int i = 0; i < TEXTURE_HASH_TABLE_SIZE; i++) {
|
||||
GLTexture *t = shared_state.texture_hash_table[i];
|
||||
while (t) {
|
||||
if (t->disposed) {
|
||||
free_texture(t);
|
||||
allDisposed = false;
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
} while (allDisposed == false);
|
||||
|
||||
Internal::tglCleanupImages();
|
||||
}
|
||||
|
||||
void GLContext::disposeDrawCallLists() {
|
||||
for (const auto &drawCall : _previousFrameDrawCallsQueue) {
|
||||
delete drawCall;
|
||||
}
|
||||
_previousFrameDrawCallsQueue.clear();
|
||||
for (auto &drawCall : _drawCallsQueue) {
|
||||
delete drawCall;
|
||||
}
|
||||
_drawCallsQueue.clear();
|
||||
}
|
||||
|
||||
static inline void _appendDirtyRectangle(const DrawCall &call, Common::List<DirtyRectangle> &rectangles, int r, int g, int b) {
|
||||
Common::Rect dirty_region = call.getDirtyRegion();
|
||||
if (rectangles.empty() || dirty_region != rectangles.back().rectangle)
|
||||
rectangles.push_back(DirtyRectangle(dirty_region, r, g, b));
|
||||
}
|
||||
|
||||
void GLContext::presentBufferDirtyRects(Common::List<Common::Rect> &dirtyAreas) {
|
||||
typedef Common::List<DrawCall *>::const_iterator DrawCallIterator;
|
||||
typedef Common::List<DirtyRectangle>::iterator RectangleIterator;
|
||||
|
||||
Common::List<DirtyRectangle> rectangles;
|
||||
|
||||
DrawCallIterator itFrame = _drawCallsQueue.begin();
|
||||
DrawCallIterator endFrame = _drawCallsQueue.end();
|
||||
DrawCallIterator itPrevFrame = _previousFrameDrawCallsQueue.begin();
|
||||
DrawCallIterator endPrevFrame = _previousFrameDrawCallsQueue.end();
|
||||
|
||||
// Compare draw calls.
|
||||
for ( ; itPrevFrame != endPrevFrame && itFrame != endFrame;
|
||||
++itPrevFrame, ++itFrame) {
|
||||
const DrawCall ¤tCall = **itFrame;
|
||||
const DrawCall &previousCall = **itPrevFrame;
|
||||
|
||||
if (previousCall != currentCall) {
|
||||
_appendDirtyRectangle(previousCall, rectangles, 255, 255, 255);
|
||||
_appendDirtyRectangle(currentCall, rectangles, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; itPrevFrame != endPrevFrame; ++itPrevFrame) {
|
||||
_appendDirtyRectangle(**itPrevFrame, rectangles, 255, 255, 255);
|
||||
}
|
||||
|
||||
for ( ; itFrame != endFrame; ++itFrame) {
|
||||
_appendDirtyRectangle(**itFrame, rectangles, 255, 0, 0);
|
||||
}
|
||||
|
||||
// This loop increases outer rectangle coordinates to favor merging of adjacent rectangles.
|
||||
for (auto &rect : rectangles) {
|
||||
rect.rectangle.right++;
|
||||
rect.rectangle.bottom++;
|
||||
}
|
||||
|
||||
// Merge coalesce dirty rects.
|
||||
bool restartMerge;
|
||||
do {
|
||||
restartMerge = false;
|
||||
for (RectangleIterator it1 = rectangles.begin(); it1 != rectangles.end(); ++it1) {
|
||||
for (RectangleIterator it2 = rectangles.begin(); it2 != rectangles.end();) {
|
||||
if (it1 != it2) {
|
||||
if ((*it1).rectangle.intersects((*it2).rectangle)) {
|
||||
(*it1).rectangle.extend((*it2).rectangle);
|
||||
it2 = rectangles.erase(it2);
|
||||
restartMerge = true;
|
||||
} else {
|
||||
++it2;
|
||||
}
|
||||
} else {
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(restartMerge);
|
||||
|
||||
for (RectangleIterator it1 = rectangles.begin(); it1 != rectangles.end(); ++it1) {
|
||||
RectangleIterator it2 = it1;
|
||||
it2++;
|
||||
while (it2 != rectangles.end()) {
|
||||
if ((*it1).rectangle.contains((*it2).rectangle)) {
|
||||
it2 = rectangles.erase(it2);
|
||||
} else {
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &rect : rectangles) {
|
||||
rect.rectangle.clip(renderRect);
|
||||
}
|
||||
|
||||
if (!rectangles.empty()) {
|
||||
for (auto &rect : rectangles) {
|
||||
dirtyAreas.push_back(rect.rectangle);
|
||||
}
|
||||
|
||||
// Execute draw calls.
|
||||
for (auto &drawCall : _drawCallsQueue) {
|
||||
Common::Rect drawCallRegion = drawCall->getDirtyRegion();
|
||||
for (auto &rect : rectangles) {
|
||||
Common::Rect dirtyRegion = rect.rectangle;
|
||||
if (dirtyRegion.intersects(drawCallRegion)) {
|
||||
drawCall->execute(true, &dirtyRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_debugRectsEnabled) {
|
||||
// Draw debug rectangles.
|
||||
// Note: white rectangles are rectangle that contained other rectangles
|
||||
// blue rectangles are rectangle merged from other rectangles
|
||||
// red rectangles are original dirty rects
|
||||
|
||||
fb->enableBlending(false);
|
||||
fb->enableAlphaTest(false);
|
||||
|
||||
for (auto &rect : rectangles) {
|
||||
debugDrawRectangle(rect.rectangle, rect.r, rect.g, rect.b);
|
||||
}
|
||||
|
||||
fb->enableBlending(blending_enabled);
|
||||
fb->enableAlphaTest(alpha_test_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose not necessary draw calls.
|
||||
for (auto &p : _previousFrameDrawCallsQueue) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
_previousFrameDrawCallsQueue = _drawCallsQueue;
|
||||
_drawCallsQueue.clear();
|
||||
|
||||
disposeResources();
|
||||
|
||||
_currentAllocatorIndex = (_currentAllocatorIndex + 1) & 0x1;
|
||||
_drawCallAllocator[_currentAllocatorIndex].reset();
|
||||
}
|
||||
|
||||
void GLContext::presentBufferSimple(Common::List<Common::Rect> &dirtyAreas) {
|
||||
dirtyAreas.push_back(Common::Rect(fb->getPixelBufferWidth(), fb->getPixelBufferHeight()));
|
||||
|
||||
for (const auto &drawCall : _drawCallsQueue) {
|
||||
drawCall->execute(true);
|
||||
delete drawCall;
|
||||
}
|
||||
|
||||
_drawCallsQueue.clear();
|
||||
|
||||
disposeResources();
|
||||
|
||||
_drawCallAllocator[_currentAllocatorIndex].reset();
|
||||
}
|
||||
|
||||
void presentBuffer(Common::List<Common::Rect> &dirtyAreas) {
|
||||
GLContext *c = gl_get_context();
|
||||
if (c->_enableDirtyRectangles) {
|
||||
c->presentBufferDirtyRects(dirtyAreas);
|
||||
} else {
|
||||
c->presentBufferSimple(dirtyAreas);
|
||||
}
|
||||
}
|
||||
|
||||
void presentBuffer() {
|
||||
Common::List<Common::Rect> dirtyAreas;
|
||||
presentBuffer(dirtyAreas);
|
||||
}
|
||||
|
||||
bool DrawCall::operator==(const DrawCall &other) const {
|
||||
if (_type == other._type) {
|
||||
switch (_type) {
|
||||
case DrawCall_Rasterization:
|
||||
return *(const RasterizationDrawCall *)this == (const RasterizationDrawCall &)other;
|
||||
break;
|
||||
case DrawCall_Blitting:
|
||||
return *(const BlittingDrawCall *)this == (const BlittingDrawCall &)other;
|
||||
break;
|
||||
case DrawCall_Clear:
|
||||
return *(const ClearBufferDrawCall *)this == (const ClearBufferDrawCall &)other;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RasterizationDrawCall::RasterizationDrawCall() : DrawCall(DrawCall_Rasterization) {
|
||||
GLContext *c = gl_get_context();
|
||||
_vertexCount = c->vertex_cnt;
|
||||
_vertex = (GLVertex *) Internal::allocateFrame(_vertexCount * sizeof(GLVertex));
|
||||
_drawTriangleFront = c->draw_triangle_front;
|
||||
_drawTriangleBack = c->draw_triangle_back;
|
||||
memcpy(_vertex, c->vertex, sizeof(GLVertex) * _vertexCount);
|
||||
_state = captureState();
|
||||
if (c->_enableDirtyRectangles) {
|
||||
computeDirtyRegion();
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizationDrawCall::computeDirtyRegion() {
|
||||
int clip_code = 0xf;
|
||||
|
||||
for (int i = 0; i < _vertexCount; i++) {
|
||||
clip_code &= _vertex[i].clip_code;
|
||||
}
|
||||
|
||||
if (!clip_code) {
|
||||
GLContext *c = gl_get_context();
|
||||
int xmax = c->fb->getPixelBufferWidth() - 1;
|
||||
int ymax = c->fb->getPixelBufferHeight() - 1;
|
||||
int left = xmax, right = 0, top = ymax, bottom = 0;
|
||||
for (int i = 0; i < _vertexCount; i++) {
|
||||
GLVertex *v = &_vertex[i];
|
||||
if (v->clip_code)
|
||||
c->gl_transform_to_viewport(v);
|
||||
left = MIN(left, v->clip_code & 0x1 ? 0 : v->zp.x);
|
||||
right = MAX(right, v->clip_code & 0x2 ? xmax : v->zp.x);
|
||||
bottom = MAX(bottom, v->clip_code & 0x4 ? ymax : v->zp.y);
|
||||
top = MIN(top, v->clip_code & 0x8 ? 0 : v->zp.y);
|
||||
}
|
||||
// Note: clipping outside of Rect is required despite above clip_code checks,
|
||||
// as vertices far on the Z axis will overflow X and/or Y coordinates.
|
||||
// This happens in EMI intro, for example.
|
||||
_dirtyRegion = Common::Rect(
|
||||
MAX(0, left),
|
||||
MAX(0, top),
|
||||
MIN(right, xmax) + 1,
|
||||
MIN(bottom, ymax) + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizationDrawCall::execute(bool restoreState, const Common::Rect *clippingRectangle) const {
|
||||
GLContext *c = gl_get_context();
|
||||
|
||||
RasterizationDrawCall::RasterizationState backupState;
|
||||
if (restoreState) {
|
||||
backupState = captureState();
|
||||
}
|
||||
applyState(_state, clippingRectangle);
|
||||
|
||||
GLVertex *prevVertex = c->vertex;
|
||||
int prevVertexCount = c->vertex_cnt;
|
||||
|
||||
c->vertex = _vertex;
|
||||
c->vertex_cnt = _vertexCount;
|
||||
c->draw_triangle_front = (gl_draw_triangle_func)_drawTriangleFront;
|
||||
c->draw_triangle_back = (gl_draw_triangle_func)_drawTriangleBack;
|
||||
|
||||
int n = c->vertex_n;
|
||||
int cnt = c->vertex_cnt;
|
||||
|
||||
switch (c->begin_type) {
|
||||
case TGL_POINTS:
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
c->gl_draw_point(&c->vertex[i]);
|
||||
}
|
||||
break;
|
||||
case TGL_LINES:
|
||||
for(int i = 0; i < cnt / 2; i++) {
|
||||
c->gl_draw_line(&c->vertex[i * 2], &c->vertex[i * 2 + 1]);
|
||||
}
|
||||
break;
|
||||
case TGL_LINE_LOOP:
|
||||
c->gl_draw_line(&c->vertex[cnt - 1], &c->vertex[0]);
|
||||
// Fall through...
|
||||
case TGL_LINE_STRIP:
|
||||
for(int i = 0; i < cnt - 1; i++) {
|
||||
c->gl_draw_line(&c->vertex[i], &c->vertex[i + 1]);
|
||||
}
|
||||
break;
|
||||
case TGL_TRIANGLES:
|
||||
for(int i = 0; i < cnt; i += 3) {
|
||||
c->gl_draw_triangle(&c->vertex[i], &c->vertex[i + 1], &c->vertex[i + 2]);
|
||||
}
|
||||
break;
|
||||
case TGL_TRIANGLE_STRIP:
|
||||
while (cnt >= 3) {
|
||||
// needed to respect triangle orientation
|
||||
switch (cnt & 1) {
|
||||
case 0:
|
||||
c->gl_draw_triangle(&c->vertex[2], &c->vertex[1], &c->vertex[0]);
|
||||
break;
|
||||
case 1:
|
||||
c->gl_draw_triangle(&c->vertex[0], &c->vertex[1], &c->vertex[2]);
|
||||
break;
|
||||
}
|
||||
cnt--;
|
||||
c->vertex++;
|
||||
}
|
||||
break;
|
||||
case TGL_TRIANGLE_FAN:
|
||||
for(int i = 1; i < cnt - 1; i++) {
|
||||
c->gl_draw_triangle(&c->vertex[0], &c->vertex[i], &c->vertex[i + 1]);
|
||||
}
|
||||
break;
|
||||
case TGL_QUADS:
|
||||
for(int i = 0; i < cnt; i += 4) {
|
||||
c->vertex[i + 2].edge_flag = 0;
|
||||
c->gl_draw_triangle(&c->vertex[i], &c->vertex[i + 1], &c->vertex[i + 2]);
|
||||
c->vertex[i + 2].edge_flag = 1;
|
||||
c->vertex[i + 0].edge_flag = 0;
|
||||
c->gl_draw_triangle(&c->vertex[i], &c->vertex[i + 2], &c->vertex[i + 3]);
|
||||
}
|
||||
break;
|
||||
case TGL_QUAD_STRIP:
|
||||
for( ; n >= 4; n -= 2) {
|
||||
c->gl_draw_triangle(&c->vertex[0], &c->vertex[1], &c->vertex[2]);
|
||||
c->gl_draw_triangle(&c->vertex[1], &c->vertex[3], &c->vertex[2]);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
c->vertex[i] = c->vertex[i + 2];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TGL_POLYGON: {
|
||||
for (int i = c->vertex_cnt; i >= 3; i--) {
|
||||
c->gl_draw_triangle(&c->vertex[i - 1], &c->vertex[0], &c->vertex[i - 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("glBegin: type %x not handled", c->begin_type);
|
||||
}
|
||||
|
||||
c->vertex = prevVertex;
|
||||
c->vertex_cnt = prevVertexCount;
|
||||
|
||||
if (restoreState) {
|
||||
applyState(backupState, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
RasterizationDrawCall::RasterizationState RasterizationDrawCall::captureState() const {
|
||||
RasterizationState state;
|
||||
GLContext *c = gl_get_context();
|
||||
state.enableScissor = c->scissor_test_enabled;
|
||||
state.enableBlending = c->blending_enabled;
|
||||
state.sfactor = c->source_blending_factor;
|
||||
state.dfactor = c->destination_blending_factor;
|
||||
state.alphaTestEnabled = c->alpha_test_enabled;
|
||||
state.alphaFunc = c->alpha_test_func;
|
||||
state.alphaRefValue = c->alpha_test_ref_val;
|
||||
state.depthTestEnabled = c->depth_test_enabled;
|
||||
state.depthFunction = c->depth_func;
|
||||
state.depthWriteMask = c->depth_write_mask;
|
||||
state.stencilTestEnabled = c->stencil_test_enabled;
|
||||
state.stencilTestFunc = c->stencil_test_func;
|
||||
state.stencilValue = c->stencil_ref_val;
|
||||
state.stencilMask = c->stencil_mask;
|
||||
state.stencilWriteMask = c->stencil_write_mask;
|
||||
state.stencilSfail = c->stencil_sfail;
|
||||
state.stencilDpfail = c->stencil_dpfail;
|
||||
state.stencilDppass = c->stencil_dppass;
|
||||
state.polygonStippleEnabled = c->polygon_stipple_enabled;
|
||||
state.offsetStates = c->offset_states;
|
||||
state.offsetFactor = c->offset_factor;
|
||||
state.offsetUnits = c->offset_units;
|
||||
|
||||
state.cullFaceEnabled = c->cull_face_enabled;
|
||||
state.beginType = c->begin_type;
|
||||
state.colorMaskRed = c->color_mask_red;
|
||||
state.colorMaskGreen = c->color_mask_green;
|
||||
state.colorMaskBlue = c->color_mask_blue;
|
||||
state.colorMaskAlpha = c->color_mask_alpha;
|
||||
state.currentFrontFace = c->current_front_face;
|
||||
state.currentShadeModel = c->current_shade_model;
|
||||
state.polygonModeBack = c->polygon_mode_back;
|
||||
state.polygonModeFront = c->polygon_mode_front;
|
||||
state.texture2DEnabled = c->texture_2d_enabled;
|
||||
state.texture = c->current_texture;
|
||||
state.wrapS = c->texture_wrap_s;
|
||||
state.wrapT = c->texture_wrap_t;
|
||||
state.textureEnv = c->_texEnv;
|
||||
state.lightingEnabled = c->lighting_enabled;
|
||||
state.textureVersion = c->current_texture->versionNumber;
|
||||
state.fogEnabled = c->fog_enabled;
|
||||
state.fogColorR = c->fog_color.X;
|
||||
state.fogColorG = c->fog_color.Y;
|
||||
state.fogColorB = c->fog_color.Z;
|
||||
state.stippleColor = c->stippleColor;
|
||||
state.two_color_stipple_enabled = c->two_color_stipple_enabled;
|
||||
|
||||
memcpy(state.scissor, c->scissor, sizeof(state.scissor));
|
||||
memcpy(state.viewportScaling, c->viewport.scale._v, sizeof(c->viewport.scale._v));
|
||||
memcpy(state.viewportTranslation, c->viewport.trans._v, sizeof(c->viewport.trans._v));
|
||||
memcpy(state.polygonStipplePattern, c->polygon_stipple_pattern, sizeof(c->polygon_stipple_pattern));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void RasterizationDrawCall::applyState(const RasterizationDrawCall::RasterizationState &state, const Common::Rect *clippingRectangle) const {
|
||||
GLContext *c = gl_get_context();
|
||||
c->fb->setupScissor(state.enableScissor, state.scissor, clippingRectangle);
|
||||
c->fb->enableBlending(state.enableBlending);
|
||||
c->fb->setBlendingFactors(state.sfactor, state.dfactor);
|
||||
c->fb->enableAlphaTest(state.alphaTestEnabled);
|
||||
c->fb->setAlphaTestFunc(state.alphaFunc, state.alphaRefValue);
|
||||
c->fb->setDepthFunc(state.depthFunction);
|
||||
c->fb->enableDepthWrite(state.depthWriteMask);
|
||||
c->fb->enableDepthTest(state.depthTestEnabled);
|
||||
c->fb->enableStencilTest(state.stencilTestEnabled);
|
||||
c->fb->setStencilWriteMask(state.stencilWriteMask);
|
||||
c->fb->setStencilTestFunc(state.stencilTestFunc, state.stencilValue, state.stencilMask);
|
||||
c->fb->setStencilOp(state.stencilSfail, state.stencilDpfail, state.stencilDppass);
|
||||
c->fb->setOffsetStates(state.offsetStates);
|
||||
c->fb->setOffsetFactor(state.offsetFactor);
|
||||
c->fb->setOffsetUnits(state.offsetUnits);
|
||||
c->fb->setFogEnabled(state.fogEnabled);
|
||||
c->fb->setFogColor(state.fogColorR, state.fogColorG, state.fogColorB);
|
||||
c->fb->setPolygonStipplePattern(state.polygonStipplePattern);
|
||||
c->fb->setStippleColor(state.stippleColor >> 16, (state.stippleColor >> 8) & 0xff, state.stippleColor & 0xff);
|
||||
c->fb->enableTwoColorStipple(state.two_color_stipple_enabled);
|
||||
c->fb->enablePolygonStipple(state.polygonStippleEnabled);
|
||||
|
||||
c->scissor_test_enabled = state.enableScissor;
|
||||
c->blending_enabled = state.enableBlending;
|
||||
c->source_blending_factor = state.sfactor;
|
||||
c->destination_blending_factor = state.dfactor;
|
||||
c->alpha_test_enabled = state.alphaTestEnabled;
|
||||
c->alpha_test_func = state.alphaFunc;
|
||||
c->alpha_test_ref_val = state.alphaRefValue;
|
||||
c->depth_test_enabled = state.depthTestEnabled;
|
||||
c->depth_func = state.depthFunction;
|
||||
c->depth_write_mask = state.depthWriteMask;
|
||||
c->stencil_test_enabled = state.stencilTestEnabled;
|
||||
c->stencil_test_func = state.stencilTestFunc;
|
||||
c->stencil_ref_val = state.stencilValue;
|
||||
c->stencil_mask = state.stencilMask;
|
||||
c->stencil_write_mask = state.stencilWriteMask;
|
||||
c->stencil_sfail = state.stencilSfail;
|
||||
c->stencil_dpfail = state.stencilDpfail;
|
||||
c->stencil_dppass = state.stencilDppass;
|
||||
c->offset_states = state.offsetStates;
|
||||
c->offset_factor = state.offsetFactor;
|
||||
c->offset_units = state.offsetUnits;
|
||||
|
||||
c->lighting_enabled = state.lightingEnabled;
|
||||
c->cull_face_enabled = state.cullFaceEnabled;
|
||||
c->begin_type = state.beginType;
|
||||
c->color_mask_red = state.colorMaskRed;
|
||||
c->color_mask_green = state.colorMaskGreen;
|
||||
c->color_mask_blue = state.colorMaskBlue;
|
||||
c->color_mask_alpha = state.colorMaskAlpha;
|
||||
c->current_front_face = state.currentFrontFace;
|
||||
c->current_shade_model = state.currentShadeModel;
|
||||
c->polygon_mode_back = state.polygonModeBack;
|
||||
c->polygon_mode_front = state.polygonModeFront;
|
||||
c->texture_2d_enabled = state.texture2DEnabled;
|
||||
c->current_texture = state.texture;
|
||||
c->texture_wrap_s = state.wrapS;
|
||||
c->texture_wrap_t = state.wrapT;
|
||||
c->_texEnv = state.textureEnv;
|
||||
c->fog_enabled = state.fogEnabled;
|
||||
c->fog_color = Vector4(state.fogColorR, state.fogColorG, state.fogColorB, 1.0f);
|
||||
|
||||
memcpy(c->scissor, state.scissor, sizeof(c->scissor));
|
||||
memcpy(c->viewport.scale._v, state.viewportScaling, sizeof(c->viewport.scale._v));
|
||||
memcpy(c->viewport.trans._v, state.viewportTranslation, sizeof(c->viewport.trans._v));
|
||||
}
|
||||
|
||||
bool RasterizationDrawCall::operator==(const RasterizationDrawCall &other) const {
|
||||
if (_vertexCount == other._vertexCount &&
|
||||
_drawTriangleFront == other._drawTriangleFront &&
|
||||
_drawTriangleBack == other._drawTriangleBack &&
|
||||
_state == other._state) {
|
||||
for (int i = 0; i < _vertexCount; i++) {
|
||||
if ((_vertex[i] != other._vertex[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BlittingDrawCall::BlittingDrawCall(BlitImage *image, const BlitTransform &transform, BlittingMode blittingMode) : DrawCall(DrawCall_Blitting), _transform(transform), _mode(blittingMode), _image(image) {
|
||||
tglIncBlitImageRef(image);
|
||||
_blitState = captureState();
|
||||
_imageVersion = tglGetBlitImageVersion(image);
|
||||
if (gl_get_context()->_enableDirtyRectangles) {
|
||||
computeDirtyRegion();
|
||||
}
|
||||
}
|
||||
|
||||
BlittingDrawCall::~BlittingDrawCall() {
|
||||
tglDeleteBlitImage(_image);
|
||||
}
|
||||
|
||||
void BlittingDrawCall::execute(bool restoreState, const Common::Rect *clippingRectangle) const {
|
||||
BlittingState backupState;
|
||||
if (restoreState) {
|
||||
backupState = captureState();
|
||||
}
|
||||
applyState(_blitState, clippingRectangle);
|
||||
|
||||
switch (_mode) {
|
||||
case BlittingDrawCall::BlitMode_Regular:
|
||||
Internal::tglBlit(_image, _transform);
|
||||
break;
|
||||
case BlittingDrawCall::BlitMode_Fast:
|
||||
Internal::tglBlitFast(_image, _transform._destinationRectangle.left, _transform._destinationRectangle.top);
|
||||
break;
|
||||
case BlittingDrawCall::BlitMode_ZBuffer:
|
||||
Internal::tglBlitZBuffer(_image, _transform._destinationRectangle.left, _transform._destinationRectangle.top);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (restoreState) {
|
||||
applyState(backupState, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
BlittingDrawCall::BlittingState BlittingDrawCall::captureState() const {
|
||||
BlittingState state;
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
state.enableScissor = c->scissor_test_enabled;
|
||||
state.enableBlending = c->blending_enabled;
|
||||
state.sfactor = c->source_blending_factor;
|
||||
state.dfactor = c->destination_blending_factor;
|
||||
state.alphaTest = c->alpha_test_enabled;
|
||||
state.alphaFunc = c->alpha_test_func;
|
||||
state.alphaRefValue = c->alpha_test_ref_val;
|
||||
state.depthTestEnabled = c->depth_test_enabled;
|
||||
|
||||
memcpy(state.scissor, c->scissor, sizeof(state.scissor));
|
||||
return state;
|
||||
}
|
||||
|
||||
void BlittingDrawCall::applyState(const BlittingState &state, const Common::Rect *clippingRectangle) const {
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
c->fb->setupScissor(state.enableScissor, state.scissor, clippingRectangle);
|
||||
c->fb->enableBlending(state.enableBlending);
|
||||
c->fb->setBlendingFactors(state.sfactor, state.dfactor);
|
||||
c->fb->enableAlphaTest(state.alphaTest);
|
||||
c->fb->setAlphaTestFunc(state.alphaFunc, state.alphaRefValue);
|
||||
c->fb->enableDepthTest(state.depthTestEnabled);
|
||||
|
||||
c->scissor_test_enabled = state.enableScissor;
|
||||
c->blending_enabled = state.enableBlending;
|
||||
c->source_blending_factor = state.sfactor;
|
||||
c->destination_blending_factor = state.dfactor;
|
||||
c->alpha_test_enabled = state.alphaTest;
|
||||
c->alpha_test_func = state.alphaFunc;
|
||||
c->alpha_test_ref_val = state.alphaRefValue;
|
||||
c->depth_test_enabled = state.depthTestEnabled;
|
||||
|
||||
memcpy(c->scissor, state.scissor, sizeof(c->scissor));
|
||||
}
|
||||
|
||||
void BlittingDrawCall::computeDirtyRegion() {
|
||||
int blitWidth = _transform._destinationRectangle.width();
|
||||
int blitHeight = _transform._destinationRectangle.height();
|
||||
if (blitWidth == 0) {
|
||||
if (_transform._sourceRectangle.width() != 0) {
|
||||
blitWidth = _transform._sourceRectangle.width();
|
||||
} else {
|
||||
tglGetBlitImageSize(_image, blitWidth, blitHeight);
|
||||
}
|
||||
}
|
||||
if (blitHeight == 0) {
|
||||
if (_transform._sourceRectangle.height() != 0) {
|
||||
blitHeight = _transform._sourceRectangle.height();
|
||||
} else {
|
||||
tglGetBlitImageSize(_image, blitWidth, blitHeight);
|
||||
}
|
||||
}
|
||||
if (blitWidth == 0 || blitHeight == 0) {
|
||||
_dirtyRegion = Common::Rect();
|
||||
} else {
|
||||
_dirtyRegion = Common::Rect(
|
||||
_transform._destinationRectangle.left,
|
||||
_transform._destinationRectangle.top,
|
||||
_transform._destinationRectangle.left + blitWidth + 1,
|
||||
_transform._destinationRectangle.top + blitHeight + 1
|
||||
);
|
||||
_dirtyRegion.clip(gl_get_context()->renderRect);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlittingDrawCall::operator==(const BlittingDrawCall &other) const {
|
||||
return
|
||||
_mode == other._mode &&
|
||||
_image == other._image &&
|
||||
_transform == other._transform &&
|
||||
_blitState == other._blitState &&
|
||||
_imageVersion == tglGetBlitImageVersion(other._image);
|
||||
}
|
||||
|
||||
|
||||
ClearBufferDrawCall::ClearBufferDrawCall(bool clearZBuffer, int zValue,
|
||||
bool clearColorBuffer, int rValue, int gValue, int bValue,
|
||||
bool clearStencilBuffer, int stencilValue)
|
||||
: _clearZBuffer(clearZBuffer), _clearColorBuffer(clearColorBuffer), _zValue(zValue),
|
||||
_rValue(rValue), _gValue(gValue), _bValue(bValue), _clearStencilBuffer(clearStencilBuffer),
|
||||
_stencilValue(stencilValue), DrawCall(DrawCall_Clear) {
|
||||
_clearState = captureState();
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
if (c->_enableDirtyRectangles) {
|
||||
_dirtyRegion = c->renderRect;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearBufferDrawCall::execute(bool restoreState, const Common::Rect *clippingRectangle) const {
|
||||
ClearBufferState backupState;
|
||||
if (restoreState) {
|
||||
backupState = captureState();
|
||||
}
|
||||
applyState(_clearState, clippingRectangle);
|
||||
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
c->fb->clear(_clearZBuffer, _zValue, _clearColorBuffer, _rValue, _gValue, _bValue, _clearStencilBuffer, _stencilValue);
|
||||
|
||||
if (restoreState) {
|
||||
applyState(backupState, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ClearBufferDrawCall::ClearBufferState ClearBufferDrawCall::captureState() const {
|
||||
ClearBufferState state;
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
state.enableScissor = c->scissor_test_enabled;
|
||||
memcpy(state.scissor, c->scissor, sizeof(state.scissor));
|
||||
return state;
|
||||
}
|
||||
|
||||
void ClearBufferDrawCall::applyState(const ClearBufferState &state, const Common::Rect *clippingRectangle) const {
|
||||
TinyGL::GLContext *c = gl_get_context();
|
||||
c->fb->setupScissor(state.enableScissor, state.scissor, clippingRectangle);
|
||||
|
||||
c->scissor_test_enabled = state.enableScissor;
|
||||
memcpy(c->scissor, state.scissor, sizeof(c->scissor));
|
||||
}
|
||||
|
||||
bool ClearBufferDrawCall::operator==(const ClearBufferDrawCall &other) const {
|
||||
return
|
||||
_clearZBuffer == other._clearZBuffer &&
|
||||
_clearColorBuffer == other._clearColorBuffer &&
|
||||
_clearStencilBuffer == other._clearStencilBuffer &&
|
||||
_rValue == other._rValue &&
|
||||
_gValue == other._gValue &&
|
||||
_bValue == other._bValue &&
|
||||
_zValue == other._zValue &&
|
||||
_stencilValue == other._stencilValue &&
|
||||
_clearState == other._clearState;
|
||||
}
|
||||
|
||||
|
||||
bool RasterizationDrawCall::RasterizationState::operator==(const RasterizationState &other) const {
|
||||
return
|
||||
enableScissor == other.enableScissor &&
|
||||
enableBlending == other.enableBlending &&
|
||||
sfactor == other.sfactor &&
|
||||
dfactor == other.dfactor &&
|
||||
alphaTestEnabled == other.alphaTestEnabled &&
|
||||
alphaFunc == other.alphaFunc &&
|
||||
alphaRefValue == other.alphaRefValue &&
|
||||
depthTestEnabled == other.depthTestEnabled &&
|
||||
depthFunction == other.depthFunction &&
|
||||
depthWriteMask == other.depthWriteMask &&
|
||||
stencilTestEnabled == other.stencilTestEnabled &&
|
||||
stencilTestFunc == other.stencilTestFunc &&
|
||||
stencilValue == other.stencilValue &&
|
||||
stencilMask == other.stencilMask &&
|
||||
stencilWriteMask == other.stencilWriteMask &&
|
||||
stencilSfail == other.stencilSfail &&
|
||||
stencilDpfail == other.stencilDpfail &&
|
||||
stencilDppass == other.stencilDppass &&
|
||||
offsetStates == other.offsetStates &&
|
||||
offsetFactor == other.offsetFactor &&
|
||||
offsetUnits == other.offsetUnits &&
|
||||
lightingEnabled == other.lightingEnabled &&
|
||||
cullFaceEnabled == other.cullFaceEnabled &&
|
||||
beginType == other.beginType &&
|
||||
colorMaskRed == other.colorMaskRed &&
|
||||
colorMaskGreen == other.colorMaskGreen &&
|
||||
colorMaskBlue == other.colorMaskBlue &&
|
||||
colorMaskAlpha == other.colorMaskAlpha &&
|
||||
currentFrontFace == other.currentFrontFace &&
|
||||
currentShadeModel == other.currentShadeModel &&
|
||||
polygonModeBack == other.polygonModeBack &&
|
||||
polygonModeFront == other.polygonModeFront &&
|
||||
texture2DEnabled == other.texture2DEnabled &&
|
||||
texture == other.texture &&
|
||||
textureVersion == texture->versionNumber &&
|
||||
fogEnabled == other.fogEnabled &&
|
||||
fogColorR == other.fogColorR &&
|
||||
fogColorG == other.fogColorG &&
|
||||
fogColorB == other.fogColorB &&
|
||||
scissor[0] == other.scissor[0] &&
|
||||
scissor[1] == other.scissor[1] &&
|
||||
scissor[2] == other.scissor[2] &&
|
||||
scissor[3] == other.scissor[3] &&
|
||||
viewportTranslation[0] == other.viewportTranslation[0] &&
|
||||
viewportTranslation[1] == other.viewportTranslation[1] &&
|
||||
viewportTranslation[2] == other.viewportTranslation[2] &&
|
||||
viewportScaling[0] == other.viewportScaling[0] &&
|
||||
viewportScaling[1] == other.viewportScaling[1] &&
|
||||
viewportScaling[2] == other.viewportScaling[2];
|
||||
}
|
||||
|
||||
void *Internal::allocateFrame(int size) {
|
||||
GLContext *c = gl_get_context();
|
||||
return c->_drawCallAllocator[c->_currentAllocatorIndex].allocate(size);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
260
graphics/tinygl/zdirtyrect.h
Normal file
260
graphics/tinygl/zdirtyrect.h
Normal file
@@ -0,0 +1,260 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_ZRECT_H
|
||||
#define GRAPHICS_TINYGL_ZRECT_H
|
||||
|
||||
#include "common/types.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "graphics/tinygl/zblit.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
namespace Internal {
|
||||
void *allocateFrame(int size);
|
||||
}
|
||||
|
||||
struct GLContext;
|
||||
struct GLVertex;
|
||||
struct GLTexture;
|
||||
|
||||
struct GLTextureEnvArgument {
|
||||
GLTextureEnvArgument();
|
||||
|
||||
uint
|
||||
sourceRGB,
|
||||
operandRGB,
|
||||
sourceAlpha,
|
||||
operandAlpha;
|
||||
};
|
||||
|
||||
struct GLTextureEnv {
|
||||
GLTextureEnv();
|
||||
bool isDefault() const;
|
||||
|
||||
uint envMode, combineRGB, combineAlpha;
|
||||
byte constA, constR, constG, constB;
|
||||
GLTextureEnvArgument arg0, arg1;
|
||||
};
|
||||
|
||||
class DrawCall {
|
||||
public:
|
||||
|
||||
enum DrawCallType {
|
||||
DrawCall_Rasterization,
|
||||
DrawCall_Blitting,
|
||||
DrawCall_Clear
|
||||
};
|
||||
|
||||
DrawCall(DrawCallType type) : _type(type) { }
|
||||
virtual ~DrawCall() { }
|
||||
bool operator==(const DrawCall &other) const;
|
||||
bool operator!=(const DrawCall &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
virtual void execute(bool restoreState, const Common::Rect *clippingRectangle = nullptr) const = 0;
|
||||
DrawCallType getType() const { return _type; }
|
||||
virtual const Common::Rect getDirtyRegion() const { return _dirtyRegion; }
|
||||
protected:
|
||||
Common::Rect _dirtyRegion;
|
||||
private:
|
||||
DrawCallType _type;
|
||||
};
|
||||
|
||||
class ClearBufferDrawCall : public DrawCall {
|
||||
public:
|
||||
ClearBufferDrawCall(bool clearZBuffer, int zValue, bool clearColorBuffer, int rValue, int gValue, int bValue, bool clearStencilBuffer, int stencilValue);
|
||||
virtual ~ClearBufferDrawCall() { }
|
||||
bool operator==(const ClearBufferDrawCall &other) const;
|
||||
virtual void execute(bool restoreState, const Common::Rect *clippingRectangle = nullptr) const;
|
||||
|
||||
void *operator new(size_t size) {
|
||||
return Internal::allocateFrame(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p) { }
|
||||
private:
|
||||
bool _clearZBuffer, _clearColorBuffer, _clearStencilBuffer;
|
||||
int _rValue, _gValue, _bValue, _zValue, _stencilValue;
|
||||
struct ClearBufferState {
|
||||
bool enableScissor;
|
||||
int scissor[4];
|
||||
|
||||
bool operator==(const ClearBufferState &other) const {
|
||||
return
|
||||
enableScissor == other.enableScissor &&
|
||||
scissor[0] == other.scissor[0] &&
|
||||
scissor[1] == other.scissor[1] &&
|
||||
scissor[2] == other.scissor[2] &&
|
||||
scissor[3] == other.scissor[3];
|
||||
}
|
||||
};
|
||||
|
||||
ClearBufferState captureState() const;
|
||||
void applyState(const ClearBufferState &state, const Common::Rect *clippingRectangle) const;
|
||||
|
||||
ClearBufferState _clearState;
|
||||
};
|
||||
|
||||
// Encapsulate a rasterization call: it might execute either a triangle or line rasterization.
|
||||
class RasterizationDrawCall : public DrawCall {
|
||||
public:
|
||||
RasterizationDrawCall();
|
||||
virtual ~RasterizationDrawCall() { }
|
||||
bool operator==(const RasterizationDrawCall &other) const;
|
||||
virtual void execute(bool restoreState, const Common::Rect *clippingRectangle = nullptr) const;
|
||||
|
||||
void *operator new(size_t size) {
|
||||
return Internal::allocateFrame(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p) { }
|
||||
private:
|
||||
void computeDirtyRegion();
|
||||
typedef void (*gl_draw_triangle_func_ptr)(GLContext *c, TinyGL::GLVertex *p0, TinyGL::GLVertex *p1, TinyGL::GLVertex *p2);
|
||||
int _vertexCount;
|
||||
GLVertex *_vertex;
|
||||
gl_draw_triangle_func_ptr _drawTriangleFront, _drawTriangleBack;
|
||||
|
||||
struct RasterizationState {
|
||||
bool enableScissor;
|
||||
int scissor[4];
|
||||
int beginType;
|
||||
int currentFrontFace;
|
||||
int cullFaceEnabled;
|
||||
bool colorMaskRed;
|
||||
bool colorMaskGreen;
|
||||
bool colorMaskBlue;
|
||||
bool colorMaskAlpha;
|
||||
bool depthTestEnabled;
|
||||
int depthFunction;
|
||||
int depthWriteMask;
|
||||
bool texture2DEnabled;
|
||||
int currentShadeModel;
|
||||
int polygonModeBack;
|
||||
int polygonModeFront;
|
||||
int lightingEnabled;
|
||||
bool enableBlending;
|
||||
int sfactor;
|
||||
int dfactor;
|
||||
int textureVersion;
|
||||
int offsetStates;
|
||||
float offsetFactor;
|
||||
float offsetUnits;
|
||||
float viewportTranslation[3];
|
||||
float viewportScaling[3];
|
||||
bool alphaTestEnabled;
|
||||
int alphaFunc;
|
||||
int alphaRefValue;
|
||||
bool stencilTestEnabled;
|
||||
int stencilTestFunc;
|
||||
byte stencilValue;
|
||||
byte stencilMask;
|
||||
byte stencilWriteMask;
|
||||
int stencilSfail;
|
||||
int stencilDpfail;
|
||||
int stencilDppass;
|
||||
bool polygonStippleEnabled;
|
||||
byte polygonStipplePattern[128];
|
||||
uint32 stippleColor;
|
||||
bool two_color_stipple_enabled;
|
||||
GLTexture *texture;
|
||||
uint wrapS, wrapT;
|
||||
GLTextureEnv textureEnv;
|
||||
bool fogEnabled;
|
||||
float fogColorR;
|
||||
float fogColorG;
|
||||
float fogColorB;
|
||||
|
||||
bool operator==(const RasterizationState &other) const;
|
||||
};
|
||||
|
||||
RasterizationState _state;
|
||||
|
||||
RasterizationState captureState() const;
|
||||
void applyState(const RasterizationState &state, const Common::Rect *clippingRectangle) const;
|
||||
};
|
||||
|
||||
// Encapsulate a blit call: it might execute either a color buffer or z buffer blit.
|
||||
class BlittingDrawCall : public DrawCall {
|
||||
public:
|
||||
enum BlittingMode {
|
||||
BlitMode_Regular,
|
||||
BlitMode_Fast,
|
||||
BlitMode_ZBuffer
|
||||
};
|
||||
|
||||
BlittingDrawCall(BlitImage *image, const BlitTransform &transform, BlittingMode blittingMode);
|
||||
virtual ~BlittingDrawCall();
|
||||
bool operator==(const BlittingDrawCall &other) const;
|
||||
virtual void execute(bool restoreState, const Common::Rect *clippingRectangle = nullptr) const;
|
||||
|
||||
BlittingMode getBlittingMode() const { return _mode; }
|
||||
|
||||
void *operator new(size_t size) {
|
||||
return Internal::allocateFrame(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p) { }
|
||||
private:
|
||||
void computeDirtyRegion();
|
||||
BlitImage *_image;
|
||||
BlitTransform _transform;
|
||||
BlittingMode _mode;
|
||||
int _imageVersion;
|
||||
|
||||
struct BlittingState {
|
||||
bool enableScissor;
|
||||
int scissor[4];
|
||||
bool enableBlending;
|
||||
int sfactor, dfactor;
|
||||
bool alphaTest;
|
||||
int alphaFunc, alphaRefValue;
|
||||
int depthTestEnabled;
|
||||
|
||||
bool operator==(const BlittingState &other) const {
|
||||
return
|
||||
enableScissor == other.enableScissor &&
|
||||
scissor[0] == other.scissor[0] &&
|
||||
scissor[1] == other.scissor[1] &&
|
||||
scissor[2] == other.scissor[2] &&
|
||||
scissor[3] == other.scissor[3] &&
|
||||
enableBlending == other.enableBlending &&
|
||||
sfactor == other.sfactor &&
|
||||
dfactor == other.dfactor &&
|
||||
alphaTest == other.alphaTest &&
|
||||
alphaFunc == other.alphaFunc &&
|
||||
alphaRefValue == other.alphaRefValue &&
|
||||
depthTestEnabled == other.depthTestEnabled;
|
||||
}
|
||||
};
|
||||
|
||||
BlittingState captureState() const;
|
||||
void applyState(const BlittingState &state, const Common::Rect *clippingRectangle) const;
|
||||
|
||||
BlittingState _blitState;
|
||||
};
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
592
graphics/tinygl/zgl.h
Normal file
592
graphics/tinygl/zgl.h
Normal file
@@ -0,0 +1,592 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#ifndef TGL_ZGL_H
|
||||
#define TGL_ZGL_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/array.h"
|
||||
#include "common/list.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/tinygl/gl.h"
|
||||
#include "graphics/tinygl/zbuffer.h"
|
||||
#include "graphics/tinygl/zmath.h"
|
||||
#include "graphics/tinygl/zblit.h"
|
||||
#include "graphics/tinygl/zdirtyrect.h"
|
||||
#include "graphics/tinygl/texelbuffer.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
enum {
|
||||
|
||||
#define ADD_OP(a,b,c) OP_ ## a ,
|
||||
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
|
||||
DUMMY
|
||||
};
|
||||
|
||||
// initially # of allocated GLVertexes (will grow when necessary)
|
||||
#define POLYGON_MAX_VERTEX 16
|
||||
|
||||
// Max # of specular light pow buffers
|
||||
#define MAX_SPECULAR_BUFFERS 8
|
||||
// # of entries in specular buffer
|
||||
#define SPECULAR_BUFFER_SIZE 1024
|
||||
// specular buffer granularity
|
||||
#define SPECULAR_BUFFER_RESOLUTION 1024
|
||||
|
||||
#define MAX_MODELVIEW_STACK_DEPTH 35
|
||||
#define MAX_PROJECTION_STACK_DEPTH 8
|
||||
#define MAX_TEXTURE_STACK_DEPTH 8
|
||||
#define MAX_NAME_STACK_DEPTH 64
|
||||
#define MAX_TEXTURE_LEVELS 11
|
||||
#define T_MAX_LIGHTS 32
|
||||
|
||||
#define VERTEX_HASH_SIZE 1031
|
||||
|
||||
#define MAX_DISPLAY_LISTS 1024
|
||||
#define OP_BUFFER_MAX_SIZE 512
|
||||
|
||||
#define TGL_OFFSET_FILL 0x1
|
||||
#define TGL_OFFSET_LINE 0x2
|
||||
#define TGL_OFFSET_POINT 0x4
|
||||
|
||||
enum eDataType {
|
||||
kIntType,
|
||||
kInt4Type,
|
||||
kUintType,
|
||||
kFloatType,
|
||||
kFloat2Type,
|
||||
kFloat4Type,
|
||||
kFloat16Type
|
||||
};
|
||||
|
||||
union uglValue {
|
||||
TGLint _int;
|
||||
TGLint _int4[4];
|
||||
TGLfloat _float;
|
||||
TGLfloat _float2[2];
|
||||
TGLfloat _float4[4];
|
||||
TGLfloat _float16[16];
|
||||
};
|
||||
|
||||
struct GLSpecBuf {
|
||||
int shininess_i;
|
||||
int last_used;
|
||||
float buf[SPECULAR_BUFFER_SIZE + 1];
|
||||
struct GLSpecBuf *next;
|
||||
};
|
||||
|
||||
struct GLLight {
|
||||
Vector4 ambient;
|
||||
Vector4 diffuse;
|
||||
Vector4 specular;
|
||||
bool has_specular;
|
||||
Vector4 position;
|
||||
Vector3 spot_direction;
|
||||
float spot_exponent;
|
||||
float spot_cutoff;
|
||||
float attenuation[3];
|
||||
// precomputed values
|
||||
float cos_spot_cutoff;
|
||||
Vector3 norm_spot_direction;
|
||||
Vector3 norm_position;
|
||||
// we use a linked list to know which are the enabled lights
|
||||
int enabled;
|
||||
struct GLLight *next, *prev;
|
||||
};
|
||||
|
||||
struct GLMaterial {
|
||||
Vector4 emission;
|
||||
Vector4 ambient;
|
||||
Vector4 diffuse;
|
||||
Vector4 specular;
|
||||
bool has_specular;
|
||||
float shininess;
|
||||
// computed values
|
||||
int shininess_i;
|
||||
int do_specular;
|
||||
};
|
||||
|
||||
struct GLViewport {
|
||||
int xmin, ymin, xsize, ysize;
|
||||
Vector3 scale;
|
||||
Vector3 trans;
|
||||
int updated;
|
||||
};
|
||||
|
||||
union GLParam {
|
||||
int op;
|
||||
float f;
|
||||
int i;
|
||||
uint ui;
|
||||
void *p;
|
||||
};
|
||||
|
||||
struct GLParamBuffer {
|
||||
GLParam ops[OP_BUFFER_MAX_SIZE];
|
||||
struct GLParamBuffer *next;
|
||||
};
|
||||
|
||||
struct GLList {
|
||||
GLParamBuffer *first_op_buffer;
|
||||
// TODO: extensions for a hash table or a better allocating scheme
|
||||
};
|
||||
|
||||
struct GLVertex {
|
||||
int edge_flag;
|
||||
Vector3 normal;
|
||||
Vector4 coord;
|
||||
Vector4 tex_coord;
|
||||
Vector4 color;
|
||||
float fog_factor;
|
||||
|
||||
// computed values
|
||||
Vector4 ec; // eye coordinates
|
||||
Vector4 pc; // coordinates in the normalized volume
|
||||
int clip_code; // clip code
|
||||
ZBufferPoint zp; // integer coordinates for the rasterization
|
||||
|
||||
bool operator==(const GLVertex &other) const {
|
||||
return
|
||||
edge_flag == other.edge_flag &&
|
||||
normal == other.normal &&
|
||||
coord == other.coord &&
|
||||
tex_coord == other.tex_coord &&
|
||||
color == other.color &&
|
||||
ec == other.ec &&
|
||||
pc == other.pc &&
|
||||
clip_code == other.clip_code &&
|
||||
zp == other.zp;
|
||||
}
|
||||
|
||||
bool operator!=(const GLVertex &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct GLImage {
|
||||
TexelBuffer *pixmap;
|
||||
int xsize, ysize;
|
||||
};
|
||||
|
||||
// textures
|
||||
|
||||
#define TEXTURE_HASH_TABLE_SIZE 256
|
||||
|
||||
struct GLTexture {
|
||||
GLImage images[MAX_TEXTURE_LEVELS];
|
||||
uint handle;
|
||||
int versionNumber;
|
||||
struct GLTexture *next, *prev;
|
||||
bool disposed;
|
||||
};
|
||||
|
||||
struct tglColorAssociation {
|
||||
Graphics::PixelFormat pf;
|
||||
TGLuint format;
|
||||
TGLuint type;
|
||||
};
|
||||
|
||||
// shared state
|
||||
|
||||
struct GLSharedState {
|
||||
GLList **lists;
|
||||
GLTexture **texture_hash_table;
|
||||
};
|
||||
|
||||
/**
|
||||
* A linear allocator implementation.
|
||||
* The allocator can be initialized to a specific buffer size only once.
|
||||
* The allocation scheme is pretty simple: pointers are returned relative to a current memory position,
|
||||
* the allocator starts with an offset of 0 and increases its offset by the allocated amount every time.
|
||||
* Memory is released through the method free(), care has to be taken to call the destructors of the deallocated objects either manually (for complex struct arrays) or
|
||||
* by overriding the delete operator (with an empty implementation).
|
||||
*/
|
||||
class LinearAllocator {
|
||||
public:
|
||||
LinearAllocator() {
|
||||
_memoryBuffer = nullptr;
|
||||
_memorySize = 0;
|
||||
_memoryPosition = 0;
|
||||
}
|
||||
|
||||
void initialize(size_t newSize) {
|
||||
assert(_memoryBuffer == nullptr);
|
||||
void *newBuffer = gl_malloc(newSize);
|
||||
if (newBuffer == nullptr) {
|
||||
error("Couldn't allocate memory for linear allocator.");
|
||||
}
|
||||
_memoryBuffer = newBuffer;
|
||||
_memorySize = newSize;
|
||||
}
|
||||
|
||||
~LinearAllocator() {
|
||||
if (_memoryBuffer != nullptr) {
|
||||
gl_free(_memoryBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void *allocate(size_t size) {
|
||||
if (_memoryPosition + size >= _memorySize) {
|
||||
error("Allocator out of memory: couldn't allocate more memory from linear allocator.");
|
||||
}
|
||||
size_t returnPos = _memoryPosition;
|
||||
_memoryPosition += size;
|
||||
return ((byte *)_memoryBuffer) + returnPos;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_memoryPosition = 0;
|
||||
}
|
||||
private:
|
||||
void *_memoryBuffer;
|
||||
size_t _memorySize;
|
||||
size_t _memoryPosition;
|
||||
};
|
||||
|
||||
struct GLContext;
|
||||
|
||||
typedef void (*gl_draw_triangle_func)(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
|
||||
// display context
|
||||
|
||||
struct GLContext {
|
||||
// Z buffer
|
||||
FrameBuffer *fb;
|
||||
Common::Rect renderRect;
|
||||
|
||||
// scissor
|
||||
bool scissor_test_enabled;
|
||||
int scissor[4];
|
||||
|
||||
// blending
|
||||
bool blending_enabled;
|
||||
int source_blending_factor;
|
||||
int destination_blending_factor;
|
||||
|
||||
// alpha blending
|
||||
bool alpha_test_enabled;
|
||||
int alpha_test_func;
|
||||
int alpha_test_ref_val;
|
||||
|
||||
// Internal texture size
|
||||
int _textureSize;
|
||||
|
||||
// lights
|
||||
GLLight lights[T_MAX_LIGHTS];
|
||||
GLLight *first_light;
|
||||
Vector4 ambient_light_model;
|
||||
int local_light_model;
|
||||
bool lighting_enabled;
|
||||
int light_model_two_side;
|
||||
|
||||
// materials
|
||||
GLMaterial materials[2];
|
||||
bool color_material_enabled;
|
||||
int current_color_material_mode;
|
||||
int current_color_material_type;
|
||||
|
||||
// textures
|
||||
GLTexture *current_texture, *default_texture;
|
||||
uint maxTextureName;
|
||||
bool texture_2d_enabled;
|
||||
int texture_mag_filter;
|
||||
int texture_min_filter;
|
||||
uint texture_wrap_s;
|
||||
uint texture_wrap_t;
|
||||
GLTextureEnv _texEnv;
|
||||
Common::Array<struct tglColorAssociation> colorAssociationList;
|
||||
|
||||
// shared state
|
||||
GLSharedState shared_state;
|
||||
|
||||
// current list
|
||||
GLParamBuffer *current_op_buffer;
|
||||
int current_op_buffer_index;
|
||||
int exec_flag, compile_flag, print_flag;
|
||||
|
||||
// matrix
|
||||
int matrix_mode;
|
||||
Matrix4 *matrix_stack[3];
|
||||
Matrix4 *matrix_stack_ptr[3];
|
||||
int matrix_stack_depth_max[3];
|
||||
|
||||
Matrix4 matrix_model_view_inv;
|
||||
Matrix4 matrix_model_projection;
|
||||
int matrix_model_projection_updated;
|
||||
int matrix_model_projection_no_w_transform;
|
||||
int apply_texture_matrix;
|
||||
|
||||
// viewport
|
||||
GLViewport viewport;
|
||||
|
||||
// current state
|
||||
int polygon_mode_back;
|
||||
int polygon_mode_front;
|
||||
|
||||
int current_front_face;
|
||||
int current_shade_model;
|
||||
int current_cull_face;
|
||||
bool cull_face_enabled;
|
||||
bool normalize_enabled;
|
||||
gl_draw_triangle_func draw_triangle_front, draw_triangle_back;
|
||||
|
||||
// selection
|
||||
int render_mode;
|
||||
uint *select_buffer;
|
||||
int select_size;
|
||||
uint *select_ptr, *select_hit;
|
||||
int select_overflow;
|
||||
int select_hits;
|
||||
|
||||
// names
|
||||
uint name_stack[MAX_NAME_STACK_DEPTH];
|
||||
int name_stack_size;
|
||||
|
||||
// clear
|
||||
float clear_depth;
|
||||
Vector4 clear_color;
|
||||
int clear_stencil;
|
||||
|
||||
// current vertex state
|
||||
Vector4 current_color;
|
||||
Vector4 current_normal;
|
||||
Vector4 current_tex_coord;
|
||||
int current_edge_flag;
|
||||
|
||||
// glBegin / glEnd
|
||||
int in_begin;
|
||||
int begin_type;
|
||||
int vertex_n, vertex_cnt;
|
||||
int vertex_max;
|
||||
GLVertex *vertex;
|
||||
|
||||
// opengl 1.1 arrays
|
||||
TGLvoid *vertex_array;
|
||||
int vertex_array_size;
|
||||
int vertex_array_stride;
|
||||
int vertex_array_type;
|
||||
TGLvoid *normal_array;
|
||||
int normal_array_stride;
|
||||
int normal_array_type;
|
||||
TGLvoid *color_array;
|
||||
int color_array_size;
|
||||
int color_array_stride;
|
||||
int color_array_type;
|
||||
TGLvoid *texcoord_array;
|
||||
int texcoord_array_size;
|
||||
int texcoord_array_stride;
|
||||
int texcoord_array_type;
|
||||
int client_states;
|
||||
|
||||
// opengl 1.1 polygon offset
|
||||
float offset_factor;
|
||||
float offset_units;
|
||||
int offset_states;
|
||||
|
||||
// specular buffer. could probably be shared between contexts,
|
||||
// but that wouldn't be 100% thread safe
|
||||
GLSpecBuf *specbuf_first;
|
||||
int specbuf_used_counter;
|
||||
int specbuf_num_buffers;
|
||||
|
||||
// opaque structure for user's use
|
||||
void *opaque;
|
||||
// resize viewport function
|
||||
int (*gl_resize_viewport)(int *xsize, int *ysize);
|
||||
|
||||
// depth test
|
||||
bool depth_test_enabled;
|
||||
int depth_func;
|
||||
bool depth_write_mask;
|
||||
|
||||
// stencil
|
||||
bool stencil_buffer_supported;
|
||||
bool stencil_test_enabled;
|
||||
int stencil_test_func;
|
||||
byte stencil_ref_val;
|
||||
byte stencil_mask;
|
||||
byte stencil_write_mask;
|
||||
int stencil_sfail;
|
||||
int stencil_dpfail;
|
||||
int stencil_dppass;
|
||||
|
||||
bool color_mask_red;
|
||||
bool color_mask_green;
|
||||
bool color_mask_blue;
|
||||
bool color_mask_alpha;
|
||||
|
||||
bool fog_enabled;
|
||||
int fog_mode;
|
||||
Vector4 fog_color;
|
||||
float fog_density;
|
||||
float fog_start;
|
||||
float fog_end;
|
||||
|
||||
bool _enableDirtyRectangles;
|
||||
|
||||
// stipple
|
||||
bool polygon_stipple_enabled;
|
||||
byte polygon_stipple_pattern[128];
|
||||
uint32 stippleColor;
|
||||
bool two_color_stipple_enabled;
|
||||
|
||||
// blit test
|
||||
Common::List<BlitImage *> _blitImages;
|
||||
|
||||
// Draw call queue
|
||||
Common::List<DrawCall *> _drawCallsQueue;
|
||||
Common::List<DrawCall *> _previousFrameDrawCallsQueue;
|
||||
int _currentAllocatorIndex;
|
||||
LinearAllocator _drawCallAllocator[2];
|
||||
bool _debugRectsEnabled;
|
||||
bool _profilingEnabled;
|
||||
|
||||
void gl_vertex_transform(GLVertex *v);
|
||||
void gl_calc_fog_factor(GLVertex *v);
|
||||
|
||||
void gl_get_pname(TGLenum pname, union uglValue *data, eDataType &dataType);
|
||||
|
||||
public:
|
||||
// The glop* functions exposed to public, however they are only for internal use.
|
||||
// Calling them from outside of TinyGL is forbidden
|
||||
#define ADD_OP(a, b, d) void glop ## a (GLParam *p);
|
||||
#include "graphics/tinygl/opinfo.h"
|
||||
|
||||
void gl_add_op(GLParam *p);
|
||||
void gl_compile_op(GLParam *p);
|
||||
|
||||
void gl_eval_viewport();
|
||||
void gl_transform_to_viewport(GLVertex *v);
|
||||
void gl_draw_triangle(GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
void gl_draw_line(GLVertex *p0, GLVertex *p1);
|
||||
void gl_draw_point(GLVertex *p0);
|
||||
|
||||
static void gl_draw_triangle_point(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
static void gl_draw_triangle_line(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
static void gl_draw_triangle_fill(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
static void gl_draw_triangle_select(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2);
|
||||
void gl_draw_triangle_clip(GLVertex *p0, GLVertex *p1, GLVertex *p2, int clip_bit);
|
||||
|
||||
void gl_add_select(uint zmin, uint zmax);
|
||||
void gl_add_select1(int z1, int z2, int z3);
|
||||
void gl_enable_disable_light(int light, int v);
|
||||
void gl_shade_vertex(GLVertex *v);
|
||||
|
||||
void gl_GetIntegerv(TGLenum pname, TGLint *data);
|
||||
void gl_GetFloatv(TGLenum pname, TGLfloat *data);
|
||||
void gl_GetDoublev(TGLenum pname, TGLdouble *data);
|
||||
void gl_GetBooleanv(TGLenum pname, TGLboolean *data);
|
||||
|
||||
void gl_EnableClientState(GLParam *p);
|
||||
void gl_DisableClientState(GLParam *p);
|
||||
void gl_VertexPointer(GLParam *p);
|
||||
void gl_ColorPointer(GLParam *p);
|
||||
void gl_NormalPointer(GLParam *p);
|
||||
void gl_TexCoordPointer(GLParam *p);
|
||||
|
||||
GLTexture *alloc_texture(uint h);
|
||||
GLTexture *find_texture(uint h);
|
||||
void free_texture(GLTexture *t);
|
||||
void gl_GenTextures(TGLsizei n, TGLuint *textures);
|
||||
void gl_DeleteTextures(TGLsizei n, const TGLuint *textures);
|
||||
void gl_PixelStore(TGLenum pname, TGLint param);
|
||||
|
||||
void issueDrawCall(DrawCall *drawCall);
|
||||
void disposeResources();
|
||||
void disposeDrawCallLists();
|
||||
|
||||
void presentBufferDirtyRects(Common::List<Common::Rect> &dirtyAreas);
|
||||
void presentBufferSimple(Common::List<Common::Rect> &dirtyAreas);
|
||||
|
||||
void debugDrawRectangle(Common::Rect rect, int r, int g, int b);
|
||||
|
||||
GLSpecBuf *specbuf_get_buffer(const int shininess_i, const float shininess);
|
||||
void specbuf_cleanup();
|
||||
|
||||
TGLint gl_RenderMode(TGLenum mode);
|
||||
void gl_SelectBuffer(TGLsizei size, TGLuint *buffer);
|
||||
|
||||
GLList *alloc_list(int list);
|
||||
GLList *find_list(uint list);
|
||||
void delete_list(int list);
|
||||
void gl_NewList(TGLuint list, TGLenum mode);
|
||||
void gl_EndList();
|
||||
TGLboolean gl_IsList(TGLuint list);
|
||||
TGLuint gl_GenLists(TGLsizei range);
|
||||
|
||||
void initSharedState();
|
||||
void endSharedState();
|
||||
|
||||
void init(int screenW, int screenH, Graphics::PixelFormat pixelFormat, int textureSize,
|
||||
bool enableStencilBuffer, bool dirtyRectsEnable, uint32 drawCallMemorySize);
|
||||
void deinit();
|
||||
|
||||
void gl_print_matrix(const float *m);
|
||||
void gl_debug(int mode) {
|
||||
print_flag = mode;
|
||||
}
|
||||
};
|
||||
|
||||
extern GLContext *gl_ctx;
|
||||
GLContext *gl_get_context();
|
||||
|
||||
#define VERTEX_ARRAY 0x0001
|
||||
#define COLOR_ARRAY 0x0002
|
||||
#define NORMAL_ARRAY 0x0004
|
||||
#define TEXCOORD_ARRAY 0x0008
|
||||
|
||||
// this clip epsilon is needed to avoid some rounding errors after
|
||||
// several clipping stages
|
||||
|
||||
#define CLIP_EPSILON (1E-5)
|
||||
|
||||
static inline int gl_clipcode(float x, float y, float z, float w1) {
|
||||
float w;
|
||||
|
||||
w = (float)(w1 * (1.0 + CLIP_EPSILON));
|
||||
return (x < -w) | ((x > w) << 1) | ((y < -w) << 2) | ((y > w) << 3) | ((z < -w) << 4) | ((z > w) << 5);
|
||||
}
|
||||
|
||||
static inline float clampf(float a, float min, float max) {
|
||||
if (a < min)
|
||||
return min;
|
||||
if (a > max)
|
||||
return max;
|
||||
else
|
||||
return a;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
201
graphics/tinygl/zline.cpp
Normal file
201
graphics/tinygl/zline.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "graphics/tinygl/zbuffer.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
template <bool kDepthWrite>
|
||||
FORCEINLINE void FrameBuffer::putPixel(uint pixelOffset, int color, int x, int y, uint z) {
|
||||
if (_clippingEnabled)
|
||||
putPixel<kDepthWrite, true>(pixelOffset, color, x, y, z);
|
||||
else
|
||||
putPixel<kDepthWrite, false>(pixelOffset, color, x, y, z);
|
||||
}
|
||||
|
||||
template <bool kDepthWrite, bool kEnableScissor>
|
||||
FORCEINLINE void FrameBuffer::putPixel(uint pixelOffset, int color, int x, int y, uint z) {
|
||||
if (kEnableScissor && scissorPixel(x, y)) {
|
||||
return;
|
||||
}
|
||||
uint *pz = _zbuf + pixelOffset;
|
||||
if (compareDepth(z, *pz)) {
|
||||
writePixel<true, true, kDepthWrite>(pixelOffset, color, z);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kEnableScissor>
|
||||
FORCEINLINE void FrameBuffer::putPixel(uint pixelOffset, int color, int x, int y) {
|
||||
if (kEnableScissor && scissorPixel(x, y)) {
|
||||
return;
|
||||
}
|
||||
writePixel<true, true>(pixelOffset, color);
|
||||
}
|
||||
|
||||
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
|
||||
void FrameBuffer::drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2) {
|
||||
if (_clippingEnabled)
|
||||
drawLine<kInterpRGB, kInterpZ, kDepthWrite, true>(p1, p2);
|
||||
else
|
||||
drawLine<kInterpRGB, kInterpZ, kDepthWrite, false>(p1, p2);
|
||||
}
|
||||
|
||||
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite, bool kEnableScissor>
|
||||
void FrameBuffer::drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2) {
|
||||
// Based on Bresenham's line algorithm, as implemented in
|
||||
// https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
|
||||
// with a loop exit condition based on the (unidimensional) taxicab
|
||||
// distance between p1 and p2 (which is cheap to compute and
|
||||
// rounding-error-free) so that interpolations are possible without
|
||||
// code duplication.
|
||||
|
||||
// Where we are in unidimensional framebuffer coordinate
|
||||
unsigned int pixelOffset = p1->y * _pbufWidth + p1->x;
|
||||
// and in 2d
|
||||
int x = p1->x;
|
||||
int y = p1->y;
|
||||
|
||||
// How to move on each axis, in both coordinates systems
|
||||
const int dx = abs(p2->x - p1->x);
|
||||
const int inc_x = p1->x < p2->x ? 1 : -1;
|
||||
const int dy = abs(p2->y - p1->y);
|
||||
const int inc_y = p1->y < p2->y ? 1 : -1;
|
||||
const int inc_y_pixel = p1->y < p2->y ? _pbufWidth : -_pbufWidth;
|
||||
|
||||
// When to move on each axis
|
||||
int err = (dx > dy ? dx : -dy) / 2;
|
||||
int e2;
|
||||
|
||||
// How many moves
|
||||
int n = dx > dy ? dx : dy;
|
||||
|
||||
// kInterpZ
|
||||
unsigned int z;
|
||||
int sz;
|
||||
|
||||
// kInterpRGB
|
||||
int r = p1->r >> (ZB_POINT_RED_BITS - 8);
|
||||
int g = p1->g >> (ZB_POINT_GREEN_BITS - 8);
|
||||
int b = p1->b >> (ZB_POINT_BLUE_BITS - 8);
|
||||
int color = RGB_TO_PIXEL(r, g, b);
|
||||
int sr, sg, sb;
|
||||
|
||||
if (kInterpZ) {
|
||||
if (n == 0)
|
||||
return;
|
||||
sz = (p2->z - p1->z) / n;
|
||||
z = p1->z;
|
||||
}
|
||||
if (kInterpRGB) {
|
||||
sr = ((p2->r - p1->r) / n) >> (ZB_POINT_RED_BITS - 8);
|
||||
sg = ((p2->g - p1->g) / n) >> (ZB_POINT_GREEN_BITS - 8);
|
||||
sb = ((p2->b - p1->b) / n) >> (ZB_POINT_BLUE_BITS - 8);
|
||||
}
|
||||
while (n--) {
|
||||
if (kInterpZ)
|
||||
putPixel<kDepthWrite, kEnableScissor>(pixelOffset, color, x, y, z);
|
||||
else
|
||||
putPixel<kEnableScissor>(pixelOffset, color, x, y);
|
||||
e2 = err;
|
||||
if (e2 > -dx) {
|
||||
err -= dy;
|
||||
pixelOffset += inc_x;
|
||||
x += inc_x;
|
||||
}
|
||||
if (e2 < dy) {
|
||||
err += dx;
|
||||
pixelOffset += inc_y_pixel;
|
||||
y += inc_y;
|
||||
}
|
||||
if (kInterpZ)
|
||||
z += sz;
|
||||
if (kInterpRGB) {
|
||||
r += sr;
|
||||
g += sg;
|
||||
b += sb;
|
||||
color = RGB_TO_PIXEL(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuffer::plot(ZBufferPoint *p) {
|
||||
const uint pixelOffset = p->y * _pbufWidth + p->x;
|
||||
const int col = RGB_TO_PIXEL(p->r, p->g, p->b);
|
||||
const uint z = p->z;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
putPixel<true>(pixelOffset, col, p->x, p->y, z);
|
||||
else
|
||||
putPixel<false>(pixelOffset, col, p->x, p->y, z);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillLineFlatZ(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
drawLine<false, true, true>(p1, p2);
|
||||
else
|
||||
drawLine<false, true, false>(p1, p2);
|
||||
}
|
||||
|
||||
// line with color interpolation
|
||||
void FrameBuffer::fillLineInterpZ(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
drawLine<true, true, true>(p1, p2);
|
||||
else
|
||||
drawLine<true, true, false>(p1, p2);
|
||||
}
|
||||
|
||||
// no Z interpolation
|
||||
void FrameBuffer::fillLineFlat(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
drawLine<false, false, true>(p1, p2);
|
||||
else
|
||||
drawLine<false, false, false>(p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillLineInterp(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
drawLine<false, true, true>(p1, p2);
|
||||
else
|
||||
drawLine<false, true, false>(p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillLineZ(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
// choose if the line should have its color interpolated or not
|
||||
if (p1->r == p2->r && p1->g == p2->g && p1->b == p2->b)
|
||||
fillLineFlatZ(p1, p2);
|
||||
else
|
||||
fillLineInterpZ(p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillLine(ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
// choose if the line should have its color interpolated or not
|
||||
if (p1->r == p2->r && p1->g == p2->g && p1->b == p2->b)
|
||||
fillLineFlat(p1, p2);
|
||||
else
|
||||
fillLineInterp(p1, p2);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
341
graphics/tinygl/zmath.cpp
Normal file
341
graphics/tinygl/zmath.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "graphics/tinygl/zmath.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
// Inversion of a 4x4 matrix.
|
||||
// It's not just unrolling, this is a different implementation that directly
|
||||
// uses the formula whereas the previous one is using another method (which is generic and thus, slower)
|
||||
static int MatrixInverse(float *m) {
|
||||
double inv[16];
|
||||
|
||||
inv[0] = m[5] * m[10] * m[15] -
|
||||
m[5] * m[11] * m[14] -
|
||||
m[9] * m[6] * m[15] +
|
||||
m[9] * m[7] * m[14] +
|
||||
m[13] * m[6] * m[11] -
|
||||
m[13] * m[7] * m[10];
|
||||
|
||||
inv[4] = -m[4] * m[10] * m[15] +
|
||||
m[4] * m[11] * m[14] +
|
||||
m[8] * m[6] * m[15] -
|
||||
m[8] * m[7] * m[14] -
|
||||
m[12] * m[6] * m[11] +
|
||||
m[12] * m[7] * m[10];
|
||||
|
||||
inv[8] = m[4] * m[9] * m[15] -
|
||||
m[4] * m[11] * m[13] -
|
||||
m[8] * m[5] * m[15] +
|
||||
m[8] * m[7] * m[13] +
|
||||
m[12] * m[5] * m[11] -
|
||||
m[12] * m[7] * m[9];
|
||||
|
||||
inv[12] = -m[4] * m[9] * m[14] +
|
||||
m[4] * m[10] * m[13] +
|
||||
m[8] * m[5] * m[14] -
|
||||
m[8] * m[6] * m[13] -
|
||||
m[12] * m[5] * m[10] +
|
||||
m[12] * m[6] * m[9];
|
||||
|
||||
inv[1] = -m[1] * m[10] * m[15] +
|
||||
m[1] * m[11] * m[14] +
|
||||
m[9] * m[2] * m[15] -
|
||||
m[9] * m[3] * m[14] -
|
||||
m[13] * m[2] * m[11] +
|
||||
m[13] * m[3] * m[10];
|
||||
|
||||
inv[5] = m[0] * m[10] * m[15] -
|
||||
m[0] * m[11] * m[14] -
|
||||
m[8] * m[2] * m[15] +
|
||||
m[8] * m[3] * m[14] +
|
||||
m[12] * m[2] * m[11] -
|
||||
m[12] * m[3] * m[10];
|
||||
|
||||
inv[9] = -m[0] * m[9] * m[15] +
|
||||
m[0] * m[11] * m[13] +
|
||||
m[8] * m[1] * m[15] -
|
||||
m[8] * m[3] * m[13] -
|
||||
m[12] * m[1] * m[11] +
|
||||
m[12] * m[3] * m[9];
|
||||
|
||||
inv[13] = m[0] * m[9] * m[14] -
|
||||
m[0] * m[10] * m[13] -
|
||||
m[8] * m[1] * m[14] +
|
||||
m[8] * m[2] * m[13] +
|
||||
m[12] * m[1] * m[10] -
|
||||
m[12] * m[2] * m[9];
|
||||
|
||||
inv[2] = m[1] * m[6] * m[15] -
|
||||
m[1] * m[7] * m[14] -
|
||||
m[5] * m[2] * m[15] +
|
||||
m[5] * m[3] * m[14] +
|
||||
m[13] * m[2] * m[7] -
|
||||
m[13] * m[3] * m[6];
|
||||
|
||||
inv[6] = -m[0] * m[6] * m[15] +
|
||||
m[0] * m[7] * m[14] +
|
||||
m[4] * m[2] * m[15] -
|
||||
m[4] * m[3] * m[14] -
|
||||
m[12] * m[2] * m[7] +
|
||||
m[12] * m[3] * m[6];
|
||||
|
||||
inv[10] = m[0] * m[5] * m[15] -
|
||||
m[0] * m[7] * m[13] -
|
||||
m[4] * m[1] * m[15] +
|
||||
m[4] * m[3] * m[13] +
|
||||
m[12] * m[1] * m[7] -
|
||||
m[12] * m[3] * m[5];
|
||||
|
||||
inv[14] = -m[0] * m[5] * m[14] +
|
||||
m[0] * m[6] * m[13] +
|
||||
m[4] * m[1] * m[14] -
|
||||
m[4] * m[2] * m[13] -
|
||||
m[12] * m[1] * m[6] +
|
||||
m[12] * m[2] * m[5];
|
||||
|
||||
inv[3] = -m[1] * m[6] * m[11] +
|
||||
m[1] * m[7] * m[10] +
|
||||
m[5] * m[2] * m[11] -
|
||||
m[5] * m[3] * m[10] -
|
||||
m[9] * m[2] * m[7] +
|
||||
m[9] * m[3] * m[6];
|
||||
|
||||
inv[7] = m[0] * m[6] * m[11] -
|
||||
m[0] * m[7] * m[10] -
|
||||
m[4] * m[2] * m[11] +
|
||||
m[4] * m[3] * m[10] +
|
||||
m[8] * m[2] * m[7] -
|
||||
m[8] * m[3] * m[6];
|
||||
|
||||
inv[11] = -m[0] * m[5] * m[11] +
|
||||
m[0] * m[7] * m[9] +
|
||||
m[4] * m[1] * m[11] -
|
||||
m[4] * m[3] * m[9] -
|
||||
m[8] * m[1] * m[7] +
|
||||
m[8] * m[3] * m[5];
|
||||
|
||||
inv[15] = m[0] * m[5] * m[10] -
|
||||
m[0] * m[6] * m[9] -
|
||||
m[4] * m[1] * m[10] +
|
||||
m[4] * m[2] * m[9] +
|
||||
m[8] * m[1] * m[6] -
|
||||
m[8] * m[2] * m[5];
|
||||
|
||||
double det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
|
||||
|
||||
if (det == 0)
|
||||
return false;
|
||||
|
||||
det = 1.0 / det;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
m[i] = inv[i] * det;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Vector3::normalize() {
|
||||
float n = sqrt(X * X + Y * Y + Z * Z);
|
||||
if (n != 0) {
|
||||
X /= n;
|
||||
Y /= n;
|
||||
Z /= n;
|
||||
}
|
||||
}
|
||||
|
||||
Vector4::Vector4(const Vector3 &vec, float w) {
|
||||
X = vec.X;
|
||||
Y = vec.Y;
|
||||
Z = vec.Z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
void Matrix4::identity() {
|
||||
memset(_m, 0, sizeof(_m));
|
||||
_m[0][0] = 1.0f;
|
||||
_m[1][1] = 1.0f;
|
||||
_m[2][2] = 1.0f;
|
||||
_m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::transpose() const {
|
||||
Matrix4 a;
|
||||
|
||||
a._m[0][0] = _m[0][0];
|
||||
a._m[0][1] = _m[1][0];
|
||||
a._m[0][2] = _m[2][0];
|
||||
a._m[0][3] = _m[3][0];
|
||||
|
||||
a._m[1][0] = _m[0][1];
|
||||
a._m[1][1] = _m[1][1];
|
||||
a._m[1][2] = _m[2][1];
|
||||
a._m[1][3] = _m[3][1];
|
||||
|
||||
a._m[2][0] = _m[0][2];
|
||||
a._m[2][1] = _m[1][2];
|
||||
a._m[2][2] = _m[2][2];
|
||||
a._m[2][3] = _m[3][2];
|
||||
|
||||
a._m[3][0] = _m[0][3];
|
||||
a._m[3][1] = _m[1][3];
|
||||
a._m[3][2] = _m[2][3];
|
||||
a._m[3][3] = _m[3][3];
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void Matrix4::transpose() {
|
||||
Matrix4 tmp = *this;
|
||||
_m[0][0] = tmp._m[0][0];
|
||||
_m[0][1] = tmp._m[1][0];
|
||||
_m[0][2] = tmp._m[2][0];
|
||||
_m[0][3] = tmp._m[3][0];
|
||||
|
||||
_m[1][0] = tmp._m[0][1];
|
||||
_m[1][1] = tmp._m[1][1];
|
||||
_m[1][2] = tmp._m[2][1];
|
||||
_m[1][3] = tmp._m[3][1];
|
||||
|
||||
_m[2][0] = tmp._m[0][2];
|
||||
_m[2][1] = tmp._m[1][2];
|
||||
_m[2][2] = tmp._m[2][2];
|
||||
_m[2][3] = tmp._m[3][2];
|
||||
|
||||
_m[3][0] = tmp._m[0][3];
|
||||
_m[3][1] = tmp._m[1][3];
|
||||
_m[3][2] = tmp._m[2][3];
|
||||
_m[3][3] = tmp._m[3][3];
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::inverseOrtho() const {
|
||||
Matrix4 a;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
a._m[i][j] = _m[j][i];
|
||||
}
|
||||
}
|
||||
a._m[3][0] = 0.0f;
|
||||
a._m[3][1] = 0.0f;
|
||||
a._m[3][2] = 0.0f;
|
||||
a._m[3][3] = 1.0f;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float s = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
s -= _m[j][i] * _m[j][3];
|
||||
}
|
||||
a._m[i][3] = s;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::inverse() const {
|
||||
Matrix4 result = *this;
|
||||
MatrixInverse((float *)result._m);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Matrix4::rotation(float t, int u) {
|
||||
float s, c;
|
||||
int v, w;
|
||||
|
||||
identity();
|
||||
|
||||
if ((v = u + 1) > 2)
|
||||
v = 0;
|
||||
if ((w = v + 1) > 2)
|
||||
w = 0;
|
||||
s = sin(t);
|
||||
c = cos(t);
|
||||
_m[v][v] = c;
|
||||
_m[v][w] = -s;
|
||||
_m[w][v] = s;
|
||||
_m[w][w] = c;
|
||||
}
|
||||
|
||||
bool Matrix4::isIdentity() const {
|
||||
//NOTE: This might need to be implemented in a fault-tolerant way.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (i == j) {
|
||||
if (_m[i][j] != 1.0) {
|
||||
return false;
|
||||
}
|
||||
} else if (_m[i][j] != 0.0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Matrix4::invert() {
|
||||
MatrixInverse((float *)_m);
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::frustum(float left, float right, float bottom, float top, float nearp, float farp) {
|
||||
float x, y, A, B, C, D;
|
||||
|
||||
x = (float)((2.0 * nearp) / (right - left));
|
||||
y = (float)((2.0 * nearp) / (top - bottom));
|
||||
A = (right + left) / (right - left);
|
||||
B = (top + bottom) / (top - bottom);
|
||||
C = -(farp + nearp) / (farp - nearp);
|
||||
D = (float)(-(2.0 * farp * nearp) / (farp - nearp));
|
||||
|
||||
Matrix4 m;
|
||||
|
||||
m._m[0][0] = x; m._m[0][1] = 0; m._m[0][2] = A; m._m[0][3] = 0;
|
||||
m._m[1][0] = 0; m._m[1][1] = y; m._m[1][2] = B; m._m[1][3] = 0;
|
||||
m._m[2][0] = 0; m._m[2][1] = 0; m._m[2][2] = C; m._m[2][3] = D;
|
||||
m._m[3][0] = 0; m._m[3][1] = 0; m._m[3][2] = -1; m._m[3][3] = 0;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void Matrix4::translate(float x, float y, float z) {
|
||||
_m[0][3] += _m[0][0] * x + _m[0][1] * y + _m[0][2] * z;
|
||||
_m[1][3] += _m[1][0] * x + _m[1][1] * y + _m[1][2] * z;
|
||||
_m[2][3] += _m[2][0] * x + _m[2][1] * y + _m[2][2] * z;
|
||||
_m[3][3] += _m[3][0] * x + _m[3][1] * y + _m[3][2] * z;
|
||||
}
|
||||
|
||||
void Matrix4::scale(float x, float y, float z) {
|
||||
_m[0][0] *= x; _m[0][1] *= y; _m[0][2] *= z;
|
||||
_m[1][0] *= x; _m[1][1] *= y; _m[1][2] *= z;
|
||||
_m[2][0] *= x; _m[2][1] *= y; _m[2][2] *= z;
|
||||
_m[3][0] *= x; _m[3][1] *= y; _m[3][2] *= z;
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
270
graphics/tinygl/zmath.h
Normal file
270
graphics/tinygl/zmath.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_TINYGL_ZMATH_H
|
||||
#define GRAPHICS_TINYGL_ZMATH_H
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
#define X _v[0]
|
||||
#define Y _v[1]
|
||||
#define Z _v[2]
|
||||
#define W _v[3]
|
||||
|
||||
// Matrix & Vertex
|
||||
class Vector3 {
|
||||
public:
|
||||
Vector3() { }
|
||||
Vector3(float x, float y, float z) {
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
void normalize();
|
||||
|
||||
float getLength() const { return sqrt(X * X + Y * Y + Z * Z); }
|
||||
|
||||
bool operator==(const Vector3 &other) const {
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector3 &other) const {
|
||||
return X != other.X || Y != other.Y || Z != other.Z;
|
||||
}
|
||||
|
||||
Vector3 operator-() const {
|
||||
return Vector3(-X, -Y, -Z);
|
||||
}
|
||||
|
||||
Vector3 operator*(float factor) const {
|
||||
return Vector3(X * factor, Y * factor, Z * factor);
|
||||
}
|
||||
|
||||
Vector3 operator+(const Vector3 &other) const {
|
||||
return Vector3(X + other.X, Y + other.Y, Z + other.Z);
|
||||
}
|
||||
|
||||
Vector3 operator-(const Vector3 &other) const {
|
||||
return Vector3(X - other.X, Y - other.Y, Z - other.Z);
|
||||
}
|
||||
|
||||
Vector3 &operator*=(float factor) {
|
||||
X *= factor;
|
||||
Y *= factor;
|
||||
Z *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &operator+=(float value) {
|
||||
X += value;
|
||||
Y += value;
|
||||
Z += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3 &operator-=(float value) {
|
||||
X -= value;
|
||||
Y -= value;
|
||||
Z -= value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float _v[3];
|
||||
};
|
||||
|
||||
class Vector4 {
|
||||
public:
|
||||
Vector4() { }
|
||||
Vector4(const Vector3 &vec, float w);
|
||||
|
||||
Vector4(float x, float y, float z, float w) {
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
bool operator==(const Vector4 &other) const {
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector4 &other) const {
|
||||
return X != other.X || Y != other.Y || Z != other.Z || W != other.W;
|
||||
}
|
||||
|
||||
Vector4 operator-() const {
|
||||
return Vector4(-X, -Y, -Z, -W);
|
||||
}
|
||||
|
||||
Vector4 operator*(float factor) const {
|
||||
return Vector4(X * factor, Y * factor, Z * factor,W * factor);
|
||||
}
|
||||
|
||||
Vector4 operator+(const Vector4 &other) const {
|
||||
return Vector4(X + other.X, Y + other.Y, Z + other.Z, W + other.W);
|
||||
}
|
||||
|
||||
Vector4 operator-(const Vector4 &other) const {
|
||||
return Vector4(X - other.X, Y - other.Y, Z - other.Z, W - other.W);
|
||||
}
|
||||
|
||||
Vector4 &operator*=(float factor) {
|
||||
X *= factor;
|
||||
Y *= factor;
|
||||
Z *= factor;
|
||||
W *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector4 &operator+=(float value) {
|
||||
X += value;
|
||||
Y += value;
|
||||
Z += value;
|
||||
W += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector4 &operator-=(float value) {
|
||||
X -= value;
|
||||
Y -= value;
|
||||
Z -= value;
|
||||
W -= value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float _v[4];
|
||||
};
|
||||
|
||||
class Matrix4 {
|
||||
public:
|
||||
Matrix4() { }
|
||||
|
||||
bool isIdentity() const;
|
||||
|
||||
inline Matrix4 operator+(const Matrix4 &b) const {
|
||||
Matrix4 result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
result._m[i][j] = _m[i][j] + b._m[i][j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Matrix4 operator-(const Matrix4 &b) const {
|
||||
Matrix4 result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
result._m[i][j] = _m[i][j] - b._m[i][j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Matrix4 operator*(const Matrix4 &b) const {
|
||||
Matrix4 result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float s = 0.0;
|
||||
for (int k = 0; k < 4; k++)
|
||||
s += _m[i][k] * b._m[k][j];
|
||||
result._m[i][j] = s;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Matrix4 &operator*=(const Matrix4 &b) {
|
||||
Matrix4 a = *this;
|
||||
float s;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
s = 0.0;
|
||||
for (int k = 0; k < 4; k++)
|
||||
s += a._m[i][k] * b._m[k][j];
|
||||
_m[i][j] = s;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void scale(float x, float y, float z);
|
||||
void translate(float x, float y, float z);
|
||||
void identity();
|
||||
void rotation(float t, int);
|
||||
|
||||
void invert();
|
||||
void transpose();
|
||||
|
||||
Matrix4 transpose() const;
|
||||
Matrix4 inverseOrtho() const;
|
||||
Matrix4 inverse() const;
|
||||
|
||||
static Matrix4 frustum(float left, float right, float bottom, float top, float nearp, float farp);
|
||||
|
||||
inline void transform(const Vector3 &vector, Vector3 &out) const {
|
||||
out.X = vector.X * _m[0][0] + vector.Y * _m[0][1] + vector.Z * _m[0][2] + _m[0][3];
|
||||
out.Y = vector.X * _m[1][0] + vector.Y * _m[1][1] + vector.Z * _m[1][2] + _m[1][3];
|
||||
out.Z = vector.X * _m[2][0] + vector.Y * _m[2][1] + vector.Z * _m[2][2] + _m[2][3];
|
||||
}
|
||||
|
||||
// Transform the vector as if this were a 3x3 matrix.
|
||||
inline void transform3x3(const Vector3 &vector, Vector3 &out) const {
|
||||
out.X = vector.X * _m[0][0] + vector.Y * _m[0][1] + vector.Z * _m[0][2];
|
||||
out.Y = vector.X * _m[1][0] + vector.Y * _m[1][1] + vector.Z * _m[1][2];
|
||||
out.Z = vector.X * _m[2][0] + vector.Y * _m[2][1] + vector.Z * _m[2][2];
|
||||
}
|
||||
|
||||
// Transform the vector as if this were a 3x3 matrix.
|
||||
inline void transform3x3(const Vector4 &vector, Vector3 &out) const {
|
||||
out.X = vector.X * _m[0][0] + vector.Y * _m[0][1] + vector.Z * _m[0][2];
|
||||
out.Y = vector.X * _m[1][0] + vector.Y * _m[1][1] + vector.Z * _m[1][2];
|
||||
out.Z = vector.X * _m[2][0] + vector.Y * _m[2][1] + vector.Z * _m[2][2];
|
||||
}
|
||||
|
||||
// Transform the vector as if this were a 3x4 matrix.
|
||||
inline void transform3x4(const Vector4 &vector, Vector4 &out) const {
|
||||
out.X = vector.X * _m[0][0] + vector.Y * _m[0][1] + vector.Z * _m[0][2] + _m[0][3];
|
||||
out.Y = vector.X * _m[1][0] + vector.Y * _m[1][1] + vector.Z * _m[1][2] + _m[1][3];
|
||||
out.Z = vector.X * _m[2][0] + vector.Y * _m[2][1] + vector.Z * _m[2][2] + _m[2][3];
|
||||
out.W = vector.X * _m[3][0] + vector.Y * _m[3][1] + vector.Z * _m[3][2] + _m[3][3];
|
||||
}
|
||||
|
||||
inline void transform(const Vector4 &vector, Vector4 &out) const {
|
||||
out.X = vector.X * _m[0][0] + vector.Y * _m[0][1] + vector.Z * _m[0][2] + vector.W * _m[0][3];
|
||||
out.Y = vector.X * _m[1][0] + vector.Y * _m[1][1] + vector.Z * _m[1][2] + vector.W * _m[1][3];
|
||||
out.Z = vector.X * _m[2][0] + vector.Y * _m[2][1] + vector.Z * _m[2][2] + vector.W * _m[2][3];
|
||||
out.W = vector.X * _m[3][0] + vector.Y * _m[3][1] + vector.Z * _m[3][2] + vector.W * _m[3][3];
|
||||
}
|
||||
|
||||
float _m[4][4];
|
||||
};
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
#endif
|
||||
850
graphics/tinygl/ztriangle.cpp
Normal file
850
graphics/tinygl/ztriangle.cpp
Normal file
@@ -0,0 +1,850 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "graphics/tinygl/texelbuffer.h"
|
||||
#include "graphics/tinygl/zbuffer.h"
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
static const int NB_INTERP = 8;
|
||||
|
||||
static bool applyStipplePattern(int x, int y, const byte *stipple) {
|
||||
|
||||
int stippleX = x % 32;
|
||||
int stippleY = y % 32;
|
||||
int byteIndex = stippleY * 4 + (stippleX / 8); // 4 bytes per row
|
||||
int bitIndex = stippleX % 8;
|
||||
|
||||
byte bitmask = 1 << (7 - bitIndex);
|
||||
return (stipple[byteIndex] & bitmask);
|
||||
}
|
||||
|
||||
template <bool kDepthWrite, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void FrameBuffer::putPixelNoTexture(int fbOffset, uint *pz, byte *ps, int _a,
|
||||
int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a,
|
||||
int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
||||
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) {
|
||||
bool useStippleColor = false;
|
||||
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (kStippleEnabled && applyStipplePattern(x + _a, y, _polygonStipplePattern)) {
|
||||
if (_twoColorStippleEnabled)
|
||||
useStippleColor = true;
|
||||
else
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (kStencilEnabled) {
|
||||
bool stencilResult = stencilTest(ps[_a]);
|
||||
if (!stencilResult) {
|
||||
stencilOp(false, true, ps + _a);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
bool depthTestResult;
|
||||
if (kDepthTestEnabled) {
|
||||
depthTestResult = compareDepth(z, pz[_a]);
|
||||
} else {
|
||||
depthTestResult = true;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
stencilOp(true, depthTestResult, ps + _a);
|
||||
}
|
||||
if (depthTestResult) {
|
||||
if (useStippleColor) {
|
||||
uint sb = (_stippleColor >> 16) & 0xFF;
|
||||
uint sg = (_stippleColor >> 8) & 0xFF;
|
||||
uint sr = _stippleColor & 0xFF;
|
||||
writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite, kFogMode>
|
||||
(fbOffset + _a, a >> (ZB_POINT_ALPHA_BITS - 8), sr, sg, sb, z, fog, fog_r, fog_g, fog_b);
|
||||
} else {
|
||||
writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite, kFogMode>
|
||||
(fbOffset + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8),
|
||||
z, fog, fog_r, fog_g, fog_b);
|
||||
}
|
||||
}
|
||||
end:
|
||||
z += dzdx;
|
||||
if (kFogMode) {
|
||||
fog += dfdx;
|
||||
}
|
||||
if (kSmoothMode) {
|
||||
r += drdx;
|
||||
g += dgdx;
|
||||
b += dbdx;
|
||||
a += dadx;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kDepthWrite, FrameBuffer::ColorMode kColorMode, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kDepthTestEnabled>
|
||||
void FrameBuffer::putPixelTexture(int fbOffset, const TexelBuffer *texture,
|
||||
uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a,
|
||||
int x, int y, uint &z, int &t, int &s,
|
||||
uint &r, uint &g, uint &b, uint &a,
|
||||
int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
||||
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) {
|
||||
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (kStencilEnabled) {
|
||||
bool stencilResult = stencilTest(ps[_a]);
|
||||
if (!stencilResult) {
|
||||
stencilOp(false, true, ps + _a);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
bool depthTestResult;
|
||||
if (kDepthTestEnabled) {
|
||||
depthTestResult = compareDepth(z, pz[_a]);
|
||||
} else {
|
||||
depthTestResult = true;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
stencilOp(true, depthTestResult, ps + _a);
|
||||
}
|
||||
if (depthTestResult) {
|
||||
uint8 c_a, c_r, c_g, c_b;
|
||||
texture->getARGBAt(wrap_s, wrap_t, s, t, c_a, c_r, c_g, c_b);
|
||||
switch (kColorMode) {
|
||||
case ColorMode::NoInterpolation:
|
||||
break;
|
||||
case ColorMode::Default:
|
||||
applyModulation(a, r, g, b, c_a, c_r, c_g, c_b);
|
||||
break;
|
||||
case ColorMode::CustomTexEnv:
|
||||
applyTextureEnvironment(
|
||||
texture->internalformat(),
|
||||
a, r, g, b,
|
||||
c_a, c_r, c_g, c_b);
|
||||
break;
|
||||
default:
|
||||
// this would be a "if constexpr" and "static_assert" on C++17
|
||||
assert(false && "Unimplemented color mode");
|
||||
break;
|
||||
}
|
||||
writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite, kFogMode>(fbOffset + _a, c_a, c_r, c_g, c_b, z, fog, fog_r, fog_g, fog_b);
|
||||
}
|
||||
end:
|
||||
z += dzdx;
|
||||
s += dsdx;
|
||||
t += dtdx;
|
||||
if (kFogMode) {
|
||||
fog += dfdx;
|
||||
}
|
||||
if (kSmoothMode) {
|
||||
a += dadx;
|
||||
r += drdx;
|
||||
g += dgdx;
|
||||
b += dbdx;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kDepthWrite, bool kEnableScissor, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void FrameBuffer::putPixelDepth(uint *pz, byte *ps, int _a, int x, int y, uint &z, int &dzdx) {
|
||||
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*if (kStippleEnabled && !applyStipplePattern(x + _a, y, _polygonStipplePattern)) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
if (kStencilEnabled) {
|
||||
bool stencilResult = stencilTest(ps[_a]);
|
||||
if (!stencilResult) {
|
||||
stencilOp(false, true, ps + _a);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
bool depthTestResult;
|
||||
if (kDepthTestEnabled) {
|
||||
depthTestResult = compareDepth(z, pz[_a]);
|
||||
} else {
|
||||
depthTestResult = true;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
stencilOp(true, depthTestResult, ps + _a);
|
||||
}
|
||||
if (kDepthWrite && depthTestResult) {
|
||||
pz[_a] = z;
|
||||
}
|
||||
end:
|
||||
z += dzdx;
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
||||
bool kDepthWrite, bool kFogMode, bool kAlphaTestEnabled, bool kEnableScissor,
|
||||
bool kBlendingEnabled, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const TexelBuffer *texture;
|
||||
float fdzdx = 0, fndzdx = 0, ndszdx = 0, ndtzdx = 0;
|
||||
|
||||
ZBufferPoint *tp, *pr1 = 0, *pr2 = 0, *l1 = 0, *l2 = 0;
|
||||
float fdx1, fdx2, fdy1, fdy2, fz0, d1, d2;
|
||||
uint *pz1 = nullptr;
|
||||
byte *ps1 = nullptr;
|
||||
int part, update_left = 1, update_right = 1;
|
||||
|
||||
int nb_lines, dx1, dy1, tmp, dx2, dy2, y;
|
||||
|
||||
int error = 0, derror = 0;
|
||||
int x1 = 0, dxdy_min = 0, dxdy_max = 0;
|
||||
// warning: x2 is multiplied by 2^16
|
||||
int x2 = 0, dx2dy2 = 0;
|
||||
|
||||
int z1 = 0, dzdx = 0, dzdy = 0, dzdl_min = 0, dzdl_max = 0;
|
||||
int f1 = 0, dfdx = 0, dfdy = 0, dfdl_min = 0, dfdl_max = 0;
|
||||
|
||||
int r1 = 0, drdx = 0, drdy = 0, drdl_min = 0, drdl_max = 0;
|
||||
int g1 = 0, dgdx = 0, dgdy = 0, dgdl_min = 0, dgdl_max = 0;
|
||||
int b1 = 0, dbdx = 0, dbdy = 0, dbdl_min = 0, dbdl_max = 0;
|
||||
int a1 = 0, dadx = 0, dady = 0, dadl_min = 0, dadl_max = 0;
|
||||
|
||||
float sz1 = 0.0, dszdx = 0, dszdy = 0, dszdl_min = 0.0, dszdl_max = 0.0;
|
||||
float tz1 = 0.0, dtzdx = 0, dtzdy = 0, dtzdl_min = 0.0, dtzdl_max = 0.0;
|
||||
|
||||
byte fog_r = 0, fog_g = 0, fog_b = 0;
|
||||
|
||||
// we sort the vertex with increasing y
|
||||
if (p1->y < p0->y) {
|
||||
tp = p0;
|
||||
p0 = p1;
|
||||
p1 = tp;
|
||||
}
|
||||
if (p2->y < p0->y) {
|
||||
tp = p2;
|
||||
p2 = p1;
|
||||
p1 = p0;
|
||||
p0 = tp;
|
||||
} else if (p2->y < p1->y) {
|
||||
tp = p1;
|
||||
p1 = p2;
|
||||
p2 = tp;
|
||||
}
|
||||
|
||||
// we compute dXdx and dXdy for all interpolated values
|
||||
|
||||
fdx1 = (float)(p1->x - p0->x);
|
||||
fdy1 = (float)(p1->y - p0->y);
|
||||
|
||||
fdx2 = (float)(p2->x - p0->x);
|
||||
fdy2 = (float)(p2->y - p0->y);
|
||||
|
||||
fz0 = fdx1 * fdy2 - fdx2 * fdy1;
|
||||
if (fz0 == 0)
|
||||
return;
|
||||
fz0 = (float)(1.0 / fz0);
|
||||
|
||||
fdx1 *= fz0;
|
||||
fdy1 *= fz0;
|
||||
fdx2 *= fz0;
|
||||
fdy2 *= fz0;
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && kFogMode) {
|
||||
fog_r = _fogColorR * 255;
|
||||
fog_g = _fogColorG * 255;
|
||||
fog_b = _fogColorB * 255;
|
||||
d1 = (float)(p1->f - p0->f);
|
||||
d2 = (float)(p2->f - p0->f);
|
||||
dfdx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
dfdy = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
}
|
||||
|
||||
if (kInterpZ) {
|
||||
d1 = (float)(p1->z - p0->z);
|
||||
d2 = (float)(p2->z - p0->z);
|
||||
dzdx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
dzdy = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
}
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && kSmoothMode) {
|
||||
d1 = (float)(p1->r - p0->r);
|
||||
d2 = (float)(p2->r - p0->r);
|
||||
drdx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
drdy = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
|
||||
d1 = (float)(p1->g - p0->g);
|
||||
d2 = (float)(p2->g - p0->g);
|
||||
dgdx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
dgdy = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
|
||||
d1 = (float)(p1->b - p0->b);
|
||||
d2 = (float)(p2->b - p0->b);
|
||||
dbdx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
dbdy = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
|
||||
d1 = (float)(p1->a - p0->a);
|
||||
d2 = (float)(p2->a - p0->a);
|
||||
dadx = (int)(fdy2 * d1 - fdy1 * d2);
|
||||
dady = (int)(fdx1 * d2 - fdx2 * d1);
|
||||
}
|
||||
|
||||
if (kInterpST || kInterpSTZ) {
|
||||
if (kInterpSTZ) {
|
||||
float zz;
|
||||
zz = (float)p0->z;
|
||||
p0->sz = (float)p0->s * zz;
|
||||
p0->tz = (float)p0->t * zz;
|
||||
zz = (float)p1->z;
|
||||
p1->sz = (float)p1->s * zz;
|
||||
p1->tz = (float)p1->t * zz;
|
||||
zz = (float)p2->z;
|
||||
p2->sz = (float)p2->s * zz;
|
||||
p2->tz = (float)p2->t * zz;
|
||||
} else {
|
||||
p0->sz = (float)p0->s;
|
||||
p0->tz = (float)p0->t;
|
||||
p1->sz = (float)p1->s;
|
||||
p1->tz = (float)p1->t;
|
||||
p2->sz = (float)p2->s;
|
||||
p2->tz = (float)p2->t;
|
||||
}
|
||||
|
||||
d1 = p1->sz - p0->sz;
|
||||
d2 = p2->sz - p0->sz;
|
||||
dszdx = (fdy2 * d1 - fdy1 * d2);
|
||||
dszdy = (fdx1 * d2 - fdx2 * d1);
|
||||
|
||||
d1 = p1->tz - p0->tz;
|
||||
d2 = p2->tz - p0->tz;
|
||||
dtzdx = (fdy2 * d1 - fdy1 * d2);
|
||||
dtzdy = (fdx1 * d2 - fdx2 * d1);
|
||||
}
|
||||
|
||||
int polyOffset = 0;
|
||||
if (kInterpZ && kColorMode != ColorMode::NoInterpolation && (_offsetStates & TGL_OFFSET_FILL)) {
|
||||
int m = MAX(ABS(dzdx), ABS(dzdy));
|
||||
polyOffset = -m * _offsetFactor + -_offsetUnits * (1 << 6);
|
||||
}
|
||||
|
||||
// screen coordinates
|
||||
|
||||
int pp1 = _pbufWidth * p0->y;
|
||||
pz1 = _zbuf + p0->y * _pbufWidth;
|
||||
if (kStencilEnabled) {
|
||||
ps1 = _sbuf + p0->y * _pbufWidth;
|
||||
}
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && !kSmoothMode) {
|
||||
r1 = p2->r;
|
||||
g1 = p2->g;
|
||||
b1 = p2->b;
|
||||
a1 = p2->a;
|
||||
}
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && (kInterpST || kInterpSTZ)) {
|
||||
texture = _currentTexture;
|
||||
fdzdx = (float)dzdx;
|
||||
fndzdx = NB_INTERP * fdzdx;
|
||||
ndszdx = NB_INTERP * dszdx;
|
||||
ndtzdx = NB_INTERP * dtzdx;
|
||||
}
|
||||
|
||||
if (fz0 > 0) {
|
||||
l1 = p0;
|
||||
l2 = p2;
|
||||
pr1 = p0;
|
||||
pr2 = p1;
|
||||
} else {
|
||||
l1 = p0;
|
||||
l2 = p1;
|
||||
pr1 = p0;
|
||||
pr2 = p2;
|
||||
}
|
||||
nb_lines = p1->y - p0->y;
|
||||
y = p0->y;
|
||||
for (part = 0; part < 2; part++) {
|
||||
if (part == 1) {
|
||||
// second part
|
||||
if (fz0 > 0) {
|
||||
update_left = 0;
|
||||
pr1 = p1;
|
||||
pr2 = p2;
|
||||
} else {
|
||||
update_right = 0;
|
||||
l1 = p1;
|
||||
l2 = p2;
|
||||
}
|
||||
nb_lines = p2->y - p1->y + 1;
|
||||
}
|
||||
|
||||
// compute the values for the left edge
|
||||
|
||||
if (update_left) {
|
||||
dy1 = l2->y - l1->y;
|
||||
dx1 = l2->x - l1->x;
|
||||
if (dy1 > 0) {
|
||||
if (dx1 < 0) {
|
||||
tmp = (-dx1 << 16) / dy1;
|
||||
tmp = -tmp;
|
||||
} else {
|
||||
tmp = (dx1 << 16) / dy1;
|
||||
}
|
||||
} else {
|
||||
tmp = 0;
|
||||
}
|
||||
x1 = l1->x;
|
||||
error = 0;
|
||||
derror = tmp & 0x0000ffff;
|
||||
dxdy_min = tmp >> 16;
|
||||
dxdy_max = dxdy_min + 1;
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && kFogMode) {
|
||||
f1 = l1->f;
|
||||
dfdl_min = (dfdy + dfdx * dxdy_min);
|
||||
dfdl_max = dfdl_min + dfdx;
|
||||
}
|
||||
|
||||
if (kInterpZ) {
|
||||
z1 = l1->z + polyOffset;
|
||||
dzdl_min = (dzdy + dzdx * dxdy_min);
|
||||
dzdl_max = dzdl_min + dzdx;
|
||||
}
|
||||
|
||||
if (kColorMode != ColorMode::NoInterpolation && kSmoothMode) {
|
||||
r1 = l1->r;
|
||||
drdl_min = (drdy + drdx * dxdy_min);
|
||||
drdl_max = drdl_min + drdx;
|
||||
|
||||
g1 = l1->g;
|
||||
dgdl_min = (dgdy + dgdx * dxdy_min);
|
||||
dgdl_max = dgdl_min + dgdx;
|
||||
|
||||
b1 = l1->b;
|
||||
dbdl_min = (dbdy + dbdx * dxdy_min);
|
||||
dbdl_max = dbdl_min + dbdx;
|
||||
|
||||
a1 = l1->a;
|
||||
dadl_min = (dady + dadx * dxdy_min);
|
||||
dadl_max = dadl_min + dadx;
|
||||
}
|
||||
|
||||
if (kInterpST || kInterpSTZ) {
|
||||
sz1 = l1->sz;
|
||||
dszdl_min = (dszdy + dszdx * dxdy_min);
|
||||
dszdl_max = dszdl_min + dszdx;
|
||||
|
||||
tz1 = l1->tz;
|
||||
dtzdl_min = (dtzdy + dtzdx * dxdy_min);
|
||||
dtzdl_max = dtzdl_min + dtzdx;
|
||||
}
|
||||
}
|
||||
|
||||
// compute values for the right edge
|
||||
|
||||
if (update_right) {
|
||||
dx2 = (pr2->x - pr1->x);
|
||||
dy2 = (pr2->y - pr1->y);
|
||||
if (dy2 > 0) {
|
||||
if (dx2 < 0) {
|
||||
dx2dy2 = (-dx2 << 16) / dy2;
|
||||
dx2dy2 = -dx2dy2;
|
||||
} else {
|
||||
dx2dy2 = (dx2 << 16) / dy2;
|
||||
}
|
||||
} else {
|
||||
dx2dy2 = 0;
|
||||
}
|
||||
x2 = pr1->x << 16;
|
||||
}
|
||||
|
||||
// we draw all the scan line of the part
|
||||
while (nb_lines > 0) {
|
||||
int x = x1;
|
||||
if (kColorMode == ColorMode::NoInterpolation) {
|
||||
int n;
|
||||
uint *pz;
|
||||
byte *ps = nullptr;
|
||||
uint z;
|
||||
n = (x2 >> 16) - x1;
|
||||
if (kInterpZ) {
|
||||
pz = pz1 + x1;
|
||||
z = z1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps = ps1 + x1;
|
||||
}
|
||||
while (n >= 3) {
|
||||
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 0, x, y, z, dzdx);
|
||||
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 1, x, y, z, dzdx);
|
||||
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 2, x, y, z, dzdx);
|
||||
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 3, x, y, z, dzdx);
|
||||
if (kInterpZ) {
|
||||
pz += 4;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += 4;
|
||||
}
|
||||
n -= 4;
|
||||
x += 4;
|
||||
}
|
||||
while (n >= 0) {
|
||||
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 0, x, y, z, dzdx);
|
||||
if (kInterpZ) {
|
||||
pz += 1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += 1;
|
||||
}
|
||||
n -= 1;
|
||||
x += 1;
|
||||
}
|
||||
} else if (!(kInterpST || kInterpSTZ)) {
|
||||
uint *pz;
|
||||
byte *ps = nullptr;
|
||||
int pp;
|
||||
uint z, r, g, b, a, fog;
|
||||
int n = (x2 >> 16) - x1;
|
||||
pp = pp1 + x1;
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
a = a1;
|
||||
if (kFogMode) {
|
||||
fog = f1;
|
||||
}
|
||||
if (kInterpZ) {
|
||||
pz = pz1 + x1;
|
||||
z = z1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps = ps1 + x1;
|
||||
}
|
||||
while (n >= 3) {
|
||||
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
||||
(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
||||
(pp, pz, ps, 1, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
||||
(pp, pz, ps, 2, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
||||
(pp, pz, ps, 3, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
pp += 4;
|
||||
if (kInterpZ) {
|
||||
pz += 4;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += 4;
|
||||
}
|
||||
n -= 4;
|
||||
x += 4;
|
||||
}
|
||||
while (n >= 0) {
|
||||
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
||||
(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
pp += 1;
|
||||
if (kInterpZ) {
|
||||
pz += 1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += 1;
|
||||
}
|
||||
n -= 1;
|
||||
x += 1;
|
||||
}
|
||||
} else if (kInterpST || kInterpSTZ) {
|
||||
uint *pz;
|
||||
byte *ps = nullptr;
|
||||
int s, t;
|
||||
uint z, r, g, b, a, fog;
|
||||
int n, pp;
|
||||
float sz, tz, fz, zinv;
|
||||
int dsdx, dtdx;
|
||||
|
||||
n = (x2 >> 16) - x1;
|
||||
fz = (float)z1;
|
||||
zinv = (float)(1.0 / fz);
|
||||
|
||||
pp = pp1 + x1;
|
||||
if (kFogMode) {
|
||||
fog = f1;
|
||||
}
|
||||
if (kInterpZ) {
|
||||
pz = pz1 + x1;
|
||||
z = z1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps = ps1 + x1;
|
||||
}
|
||||
sz = sz1;
|
||||
tz = tz1;
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
a = a1;
|
||||
while (n >= (NB_INTERP - 1)) {
|
||||
{
|
||||
float ss, tt;
|
||||
ss = sz * zinv;
|
||||
tt = tz * zinv;
|
||||
s = (int)ss;
|
||||
t = (int)tt;
|
||||
dsdx = (int)((dszdx - ss * fdzdx) * zinv);
|
||||
dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
|
||||
fz += fndzdx;
|
||||
zinv = (float)(1.0 / fz);
|
||||
}
|
||||
for (int _a = 0; _a < NB_INTERP; _a++) {
|
||||
putPixelTexture<kDepthWrite, kColorMode, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kDepthTestEnabled>
|
||||
(pp, texture, _wrapS, _wrapT, pz, ps, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
}
|
||||
pp += NB_INTERP;
|
||||
if (kInterpZ) {
|
||||
pz += NB_INTERP;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += NB_INTERP;
|
||||
}
|
||||
sz += ndszdx;
|
||||
tz += ndtzdx;
|
||||
n -= NB_INTERP;
|
||||
x += NB_INTERP;
|
||||
}
|
||||
|
||||
{
|
||||
float ss, tt;
|
||||
ss = sz * zinv;
|
||||
tt = tz * zinv;
|
||||
s = (int)ss;
|
||||
t = (int)tt;
|
||||
dsdx = (int)((dszdx - ss * fdzdx) * zinv);
|
||||
dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
|
||||
}
|
||||
|
||||
while (n >= 0) {
|
||||
putPixelTexture<kDepthWrite, kColorMode, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kDepthTestEnabled>
|
||||
(pp, texture, _wrapS, _wrapT, pz, ps, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
||||
pp += 1;
|
||||
if (kInterpZ) {
|
||||
pz += 1;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps += 1;
|
||||
}
|
||||
n -= 1;
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// left edge
|
||||
error += derror;
|
||||
if (error > 0) {
|
||||
error -= 0x10000;
|
||||
x1 += dxdy_max;
|
||||
if (kColorMode != ColorMode::NoInterpolation && kFogMode) {
|
||||
f1 += dfdl_max;
|
||||
}
|
||||
if (kInterpZ) {
|
||||
z1 += dzdl_max;
|
||||
}
|
||||
if (kColorMode != ColorMode::NoInterpolation && kSmoothMode) {
|
||||
r1 += drdl_max;
|
||||
g1 += dgdl_max;
|
||||
b1 += dbdl_max;
|
||||
a1 += dadl_max;
|
||||
}
|
||||
if (kInterpST || kInterpSTZ) {
|
||||
sz1 += dszdl_max;
|
||||
tz1 += dtzdl_max;
|
||||
}
|
||||
} else {
|
||||
x1 += dxdy_min;
|
||||
if (kColorMode != ColorMode::NoInterpolation && kFogMode) {
|
||||
f1 += dfdl_min;
|
||||
}
|
||||
if (kInterpZ) {
|
||||
z1 += dzdl_min;
|
||||
}
|
||||
if (kColorMode != ColorMode::NoInterpolation && kSmoothMode) {
|
||||
r1 += drdl_min;
|
||||
g1 += dgdl_min;
|
||||
b1 += dbdl_min;
|
||||
a1 += dadl_min;
|
||||
}
|
||||
if (kInterpST || kInterpSTZ) {
|
||||
sz1 += dszdl_min;
|
||||
tz1 += dtzdl_min;
|
||||
}
|
||||
}
|
||||
|
||||
// right edge
|
||||
x2 += dx2dy2;
|
||||
|
||||
// screen coordinates
|
||||
if (kColorMode != ColorMode::NoInterpolation) {
|
||||
pp1 += _pbufWidth;
|
||||
}
|
||||
if (kInterpZ) {
|
||||
pz1 += _pbufWidth;
|
||||
}
|
||||
if (kStencilEnabled) {
|
||||
ps1 += _pbufWidth;
|
||||
}
|
||||
|
||||
nb_lines--;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kStippleEnabled>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_depthTestEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, kStippleEnabled, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, kStippleEnabled, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_polygonStippleEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_sbuf && _stencilTestEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_blendingEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_clippingEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_alphaTestEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <FrameBuffer::ColorMode kColorMode, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite>
|
||||
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
if (_fogEnabled) {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, true>(p0, p1, p2);
|
||||
} else {
|
||||
fillTriangle<kColorMode, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, false>(p0, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite>
|
||||
void FrameBuffer::fillTriangleTextureMapping(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
// some color interpolation is implied by the texture mapping
|
||||
if (_textureEnv->isDefault())
|
||||
fillTriangle<ColorMode::Default, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite>(p0, p1, p2);
|
||||
else
|
||||
fillTriangle<ColorMode::CustomTexEnv, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite>(p0, p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const bool interpZ = true;
|
||||
const ColorMode colorMode = ColorMode::NoInterpolation;
|
||||
const bool interpST = false;
|
||||
const bool interpSTZ = false;
|
||||
const bool smoothMode = false;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
||||
else
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillTriangleFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const bool interpZ = true;
|
||||
const ColorMode colorMode = ColorMode::Default;
|
||||
const bool interpST = false;
|
||||
const bool interpSTZ = false;
|
||||
const bool smoothMode = false;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
||||
else
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
||||
}
|
||||
|
||||
// Smooth filled triangle.
|
||||
void FrameBuffer::fillTriangleSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const bool interpZ = true;
|
||||
const ColorMode colorMode = ColorMode::Default;
|
||||
const bool interpST = false;
|
||||
const bool interpSTZ = false;
|
||||
const bool smoothMode = true;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
||||
else
|
||||
fillTriangle<colorMode, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const bool interpZ = true;
|
||||
const bool interpST = true;
|
||||
const bool interpSTZ = true;
|
||||
const bool smoothMode = true;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
fillTriangleTextureMapping<interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
||||
else
|
||||
fillTriangleTextureMapping<interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
||||
}
|
||||
|
||||
void FrameBuffer::fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
||||
const bool interpZ = true;
|
||||
const bool interpST = false;
|
||||
const bool interpSTZ = true;
|
||||
const bool smoothMode = false;
|
||||
if (_depthWrite && _depthTestEnabled)
|
||||
fillTriangleTextureMapping<interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
||||
else
|
||||
fillTriangleTextureMapping<interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
Reference in New Issue
Block a user