Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Graphics/drawbatch.cpp')
-rw-r--r--Source/Graphics/drawbatch.cpp520
1 files changed, 520 insertions, 0 deletions
diff --git a/Source/Graphics/drawbatch.cpp b/Source/Graphics/drawbatch.cpp
new file mode 100644
index 00000000..112ffa43
--- /dev/null
+++ b/Source/Graphics/drawbatch.cpp
@@ -0,0 +1,520 @@
+//-----------------------------------------------------------------------------
+// Name: drawbatch.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "drawbatch.h"
+
+#include <Graphics/textures.h>
+#include <Graphics/shaders.h>
+#include <Graphics/graphics.h>
+#include <Graphics/camera.h>
+
+#include <Timing/timingevent.h>
+#include <Timing/intel_gl_perf.h>
+
+#include <Internal/timer.h>
+#include <Main/scenegraph.h>
+
+extern SceneLight* primary_light;
+extern Timer game_timer;
+
+//-----------------------------------------------------------------------------
+//Functions
+//-----------------------------------------------------------------------------
+
+void DrawBatch::AddUniformMat3(std::string _name, const GLfloat *_data) {
+ uniforms.resize(uniforms.size()+1);
+ uniforms.back().name = _name;
+ uniforms.back().type = _mat3;
+ uniforms.back().data.resize(9);
+ memcpy(&uniforms.back().data[0], _data, 9*sizeof(GLfloat));
+}
+
+void DrawBatch::AddUniformMat4(std::string _name, const GLfloat *_data) {
+ uniforms.resize(uniforms.size()+1);
+ uniforms.back().name = _name;
+ uniforms.back().type = _mat4;
+ uniforms.back().data.resize(16);
+ memcpy(&uniforms.back().data[0], _data, 16*sizeof(GLfloat));
+}
+
+void DrawBatch::AddUniformFloat( std::string _name, GLfloat data ) {
+ uniforms.resize(uniforms.size()+1);
+ uniforms.back().name = _name;
+ uniforms.back().type = _float;
+ uniforms.back().data.resize(1);
+ uniforms.back().data[0] = data;
+}
+
+void DrawBatch::AddUniformVec3( std::string _name, const GLfloat *_data ) {
+ uniforms.resize(uniforms.size()+1);
+ uniforms.back().name = _name;
+ uniforms.back().type = _vec3;
+ uniforms.back().data.resize(3);
+ memcpy(&uniforms.back().data[0], _data, 3*sizeof(GLfloat));
+}
+
+void DrawBatch::AddUniformVec3( std::string _name, const vec3 &_data )
+{
+ AddUniformVec3(_name, (const GLfloat*)&_data);
+}
+
+DrawBatch::DrawBatch() : visible(true),
+ no_vbo(false),
+ normal_ptr(NULL),
+ vertex_ptr(NULL),
+ face_ptr(NULL),
+ num_face_ids(0),
+ draw_times(0),
+ use_cam_pos(false),
+ use_time(false),
+ use_light(false),
+ transparent(false),
+ depth_func(GL_LEQUAL),
+ polygon_offset(false),
+ shader_id(-1),
+ to_delete(false)
+{
+ color = vec4(1.0f);
+ for(int i=0; i<8; i++){
+ tex_coord_ptr[i] = NULL;
+ tex_coord_elements[i] = 0;
+ use_vbo_texcoords[i] = true;
+ }
+ for(int i=0; i<kMaxTextures; i++){
+ texture_ref[i].clear();
+ }
+}
+
+void DrawBatch::Draw() {
+ if(to_delete || vertices.empty()){
+ return;
+ }
+
+ if(!vbo_vertices->valid() && draw_times > _vbo_threshold && !no_vbo){
+ CreateVBO(DrawBatch::FACE_VBO);
+ }
+
+ if(added_batches.empty()){
+ SetStartState();
+ SetupVertexArrays();
+
+ Graphics::Instance()->SetModelMatrix(transform, inv_transpose_transform);
+
+ DrawVertexArrays();
+ SetEndState();
+ EndVertexArrays();
+ } else {
+ const Camera& camera = (*ActiveCameras::Get());
+ SetupVertexArrays();
+ for(unsigned i=0; i<added_batches.size(); i++){
+ if(camera.checkSphereInFrustum(added_batches[i].batch->bounding_sphere_center,
+ added_batches[i].batch->bounding_sphere_radius)){
+ added_batches[i].batch->SetStartState();
+ //glPushMatrix();
+ //glMultMatrixf(added_batches[i].batch->transform);
+
+ Graphics::Instance()->SetModelMatrix(added_batches[i].batch->transform, added_batches[i].batch->inv_transpose_transform);
+
+ DrawVertexArrayRange(added_batches[i].start_face,
+ added_batches[i].end_face,
+ added_batches[i].start_vertex,
+ added_batches[i].end_vertex);
+ //glPopMatrix();
+ added_batches[i].batch->SetEndState();
+ }
+ }
+ EndVertexArrays();
+ }
+
+ draw_times++;
+}
+
+void DrawBatch::CreateVBO(CreateVBOParam create_vbo_param) {
+ if(create_vbo_param == FACE_VBO){
+ vbo_faces->Fill(kVBOElement | kVBOStatic, faces.size()*sizeof(GLuint),&faces[0]);
+ }
+ vbo_vertices->Fill(kVBOFloat | kVBOStatic, vertices.size()*sizeof(GLfloat),&vertices[0]);
+ if(!normals.empty()){
+ vbo_normals->Fill(kVBOFloat | kVBOStatic, normals.size()*sizeof(GLfloat),&normals[0]);
+ }
+ for(int i=0; i<8; i++){
+ vbo_tex_coords[i]->Dispose();
+ if(!tex_coords[i].empty() && use_vbo_texcoords[i]) {
+ vbo_tex_coords[i]->Fill(kVBOFloat | kVBOStatic, tex_coords[i].size()*sizeof(GLfloat),&tex_coords[i][0]);
+ }
+ }
+}
+
+void DrawBatch::TexCoordPointer( int size, GLfloat* data, int which_tex ) {
+ tex_coord_ptr[which_tex] = data;
+ tex_coord_elements[which_tex] = size;
+}
+
+void DrawBatch::VertexPointer( GLfloat* data ) {
+ vertex_ptr = data;
+}
+
+void DrawBatch::NormalPointer( GLfloat* data ) {
+ normal_ptr = data;
+}
+
+void DrawBatch::DrawElements( GLuint size, const GLuint* data ) {
+ face_ptr = data;
+ num_face_ids = size;
+
+ faces.resize(num_face_ids);
+ memcpy(&faces[0],face_ptr,num_face_ids*sizeof(GLuint));
+
+ GLuint max_vertex_id = 0;
+ for(unsigned i=0; i<num_face_ids; i++){
+ max_vertex_id = max(max_vertex_id,face_ptr[i]);
+ }
+
+ int num_vertices = max_vertex_id + 1;
+
+ if(normal_ptr){
+ normals.resize(num_vertices*3);
+ memcpy(&normals[0],normal_ptr,normals.size()*sizeof(GLfloat));
+ }
+
+ if(vertex_ptr){
+ vertices.resize(num_vertices*3);
+ memcpy(&vertices[0],vertex_ptr,vertices.size()*sizeof(GLfloat));
+ }
+
+ for(int i=0; i<8; i++){
+ if(tex_coord_ptr[i]){
+ tex_coords[i].resize(num_vertices*tex_coord_elements[i]);
+ memcpy(&tex_coords[i][0],tex_coord_ptr[i],tex_coords[i].size()*sizeof(GLfloat));
+ }
+ }
+
+ face_ptr = NULL;
+ normal_ptr = NULL;
+ vertex_ptr = NULL;
+ for(int i=0; i<8; i++){
+ tex_coord_ptr[i] = NULL;
+ }
+}
+
+void DrawBatch::AddBatch( const DrawBatch &other ) {
+ if(other.to_delete || other.faces.empty()){
+ return;
+ }
+
+ if(other.added_batches.size()){
+ for(unsigned i=0; i<other.added_batches.size(); i++){
+ AddBatch(*(other.added_batches[i].batch));
+ }
+ return;
+ }
+
+ if(vertices.empty()){
+ (*this)=other;
+ added_batches.resize(added_batches.size()+1);
+ added_batches.back().batch = &other;
+ added_batches.back().start_face = 0;
+ added_batches.back().end_face = other.faces.size();
+ added_batches.back().start_vertex = 0;
+ added_batches.back().end_vertex = other.vertices.size()/3;
+ return;
+ }
+
+ int existing_vertices = vertices.size();
+ int existing_faces = faces.size();
+
+ added_batches.resize(added_batches.size()+1);
+ added_batches.back().batch = &other;
+ added_batches.back().start_face = existing_faces;
+ added_batches.back().end_face = existing_faces+other.faces.size();
+
+ faces.resize(faces.size()+other.faces.size());
+ memcpy(&faces[existing_faces],
+ &other.faces[0],
+ other.faces.size()*sizeof(GLuint));
+
+ num_face_ids += other.num_face_ids;
+
+ int existing_complete_vertices = existing_vertices/3;
+ for(unsigned i=existing_faces; i<faces.size(); i++){
+ faces[i] += existing_complete_vertices;
+ }
+
+ added_batches.back().start_vertex = existing_complete_vertices;
+ added_batches.back().end_vertex = existing_complete_vertices + other.vertices.size()/3;
+
+ normals.resize(normals.size()+other.normals.size());
+ memcpy(&normals[existing_vertices],
+ &other.normals[0],
+ other.normals.size()*sizeof(GLfloat));
+
+ vertices.resize(vertices.size()+other.vertices.size());
+ memcpy(&vertices[existing_vertices],
+ &other.vertices[0],
+ other.vertices.size()*sizeof(GLfloat));
+
+
+ for(int i=0; i<8; i++){
+ if(!tex_coords[i].empty()){
+ tex_coords[i].resize(tex_coords[i].size()+other.tex_coords[i].size());
+ memcpy(&tex_coords[i][existing_vertices],
+ &other.tex_coords[i][0],
+ other.tex_coords[i].size()*sizeof(GLfloat));
+ }
+ }
+}
+
+
+void Uniform::Apply() const {
+ CHECK_GL_ERROR();
+ int bound_program = Shaders::Instance()->bound_program;
+ GLint var = Shaders::Instance()->returnShaderVariable(name,bound_program);
+
+ switch(type){
+ case _mat3:
+ Shaders::Instance()->SetUniformMat3(var,&data[0]);
+ break;
+ case _mat4:
+ Shaders::Instance()->SetUniformMat4(var,&data[0]);
+ break;
+ case _vec3:
+ Shaders::Instance()->SetUniformVec3(var,&data[0]);
+ break;
+ case _vec4:
+ Shaders::Instance()->SetUniformVec4(var,&data[0]);
+ break;
+ case _float:
+ Shaders::Instance()->SetUniformFloat(var,data[0]);
+ break;
+ default:
+ //mjh - what's the reasonable thing to do here?
+ break;
+ }
+ CHECK_GL_ERROR();
+}
+
+Uniform::Uniform():
+ individual(false)
+{
+}
+
+void DrawBatch::Dispose() {
+ normals.clear();
+ vertices.clear();
+ for(int i=0; i<8; i++){
+ tex_coords[i].clear();
+ }
+ faces.clear();
+ uniforms.clear();
+
+ vbo_faces->Dispose();
+ vbo_vertices->Dispose();
+ vbo_normals->Dispose();
+ for(int i=0; i<8; i++){
+ vbo_tex_coords[i]->Dispose();
+ }
+
+ draw_times = 0;
+}
+
+void DrawBatch::SetStartState() const {
+ Graphics* graphics = Graphics::Instance();
+ Shaders* shaders = Shaders::Instance();
+ Textures* textures = Textures::Instance();
+
+ graphics->setDepthFunc(depth_func);
+ graphics->setPolygonOffset(polygon_offset);
+ graphics->setGLState(gl_state);
+
+ shaders->setProgram(shader_id);
+
+ for(unsigned i=0; i<uniforms.size(); i++){
+ uniforms[i].Apply();
+ }
+
+ if(use_cam_pos){
+ shaders->SetUniformVec3("cam_pos",ActiveCameras::Get()->GetPos());
+ }
+
+ if(use_time){
+ shaders->SetUniformFloat("time",game_timer.GetRenderTime());
+ }
+
+ if(use_light){
+ shaders->SetUniformVec3("ws_light",primary_light->pos);
+ shaders->SetUniformVec4("primary_light_color",vec4(primary_light->color, primary_light->intensity));
+ }
+
+ shaders->SetUniformVec4("uniform_color", color);
+
+ for(int i=0; i<kMaxTextures; i++) {
+ if(texture_ref[i].valid()) {
+ textures->bindTexture(texture_ref[i], i);
+ }
+ }
+
+ if(transparent && graphics->use_sample_alpha_to_coverage){
+ glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE );
+ }
+}
+
+void DrawBatch::EndVertexArrays() const {
+ for(int i=1; i<8; i++){
+ if(!tex_coords[i].empty()){
+ Graphics::Instance()->SetClientStateEnabled(CS_TEXTURE_COORD_ARRAY0 + i,false);
+ }
+ }
+ Graphics::Instance()->SetClientActiveTexture(0);
+
+ Graphics::Instance()->BindArrayVBO(0);
+ Graphics::Instance()->BindElementVBO(0);
+}
+
+void DrawBatch::SetEndState() const {
+ if(transparent && Graphics::Instance()->use_sample_alpha_to_coverage){
+ glDisable( GL_SAMPLE_ALPHA_TO_COVERAGE );
+ }
+}
+
+void DrawBatch::DrawVertexArrays() const {
+ if(vbo_faces.GetConst().valid()){
+ Graphics::Instance()->DrawElements(GL_TRIANGLES, num_face_ids, GL_UNSIGNED_INT, 0);
+ } else {
+ Graphics::Instance()->DrawElements(GL_TRIANGLES, num_face_ids, GL_UNSIGNED_INT, &faces[0]);
+ }
+}
+
+void DrawBatch::DrawVertexArrayRange(GLuint start, GLuint end, GLuint start_vertex, GLuint end_vertex) const {
+ if(vbo_faces.GetConst().valid()){
+ //glDrawElements(GL_TRIANGLES, num_face_ids, GL_UNSIGNED_INT, 0);
+ Graphics::Instance()->DrawRangeElements(GL_TRIANGLES, start_vertex, end_vertex, end-start, GL_UNSIGNED_INT, (char*)NULL+start*sizeof(GLuint));
+ } else {
+ Graphics::Instance()->DrawRangeElements(GL_TRIANGLES, start_vertex, end_vertex, end-start, GL_UNSIGNED_INT, &faces[start]);
+ }
+}
+
+void DrawBatch::SetupVertexArrays() const {
+ Graphics *graphics = Graphics::Instance();
+ graphics->SetClientStates(F_VERTEX_ARRAY | F_NORMAL_ARRAY | F_TEXTURE_COORD_ARRAY0);
+
+ for(int i=0; i<8; i++){
+ if(!tex_coords[i].empty()){
+ graphics->SetClientStateEnabled(CS_TEXTURE_COORD_ARRAY0 + i,true);
+ if(vbo_tex_coords[i].GetConst().valid()){
+ vbo_tex_coords[i].GetConst().Bind();
+ glTexCoordPointer(tex_coord_elements[i], GL_FLOAT, 0, 0);
+ } else {
+ graphics->BindArrayVBO(0);
+ glTexCoordPointer(tex_coord_elements[i], GL_FLOAT, 0, &tex_coords[i][0]);
+ }
+ }
+ }
+
+ if(vbo_normals.GetConst().valid()){
+ vbo_normals.GetConst().Bind();
+ glNormalPointer(GL_FLOAT, 0, 0);
+ } else if(!normals.empty()) {
+ graphics->BindArrayVBO(0);
+ glNormalPointer(GL_FLOAT, 0, &normals[0]);
+ }
+
+ if(vbo_vertices.GetConst().valid()){
+ vbo_vertices.GetConst().Bind();
+ glVertexPointer(3, GL_FLOAT, 0, 0);
+ } else {
+ graphics->BindArrayVBO(0);
+ glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
+ }
+
+ if(vbo_faces.GetConst().valid()){
+ vbo_faces.GetConst().Bind();
+ }
+}
+
+void DrawBatch::SetUniformFloat( std::string _name, GLfloat data )
+{
+ for(unsigned i=0; i<uniforms.size(); ++i){
+ if(uniforms[i].name == _name){
+ uniforms[i].data[0] = data;
+ return;
+ }
+ }
+ AddUniformFloat(_name, data);
+}
+
+void DrawBatch::MakeUniformIndividual( std::string _name )
+{
+ for(unsigned i=0; i<uniforms.size(); ++i){
+ if(uniforms[i].name == _name){
+ uniforms[i].individual = true;
+ }
+ }
+}
+
+void DrawBatch::ApplyIndividualUniforms() const
+{
+ for(unsigned i=0; i<uniforms.size(); i++){
+ if(uniforms[i].individual){
+ uniforms[i].Apply();
+ }
+ }
+}
+
+void DrawBatch::SetUniformVec3( std::string _name, const vec3 &_data )
+{
+ for(unsigned i=0; i<uniforms.size(); ++i){
+ if(uniforms[i].name == _name){
+ memcpy(&uniforms[i].data[0],
+ (const GLfloat*)_data.entries,
+ 3*sizeof(GLfloat));
+ }
+ }
+}
+
+void DrawBatch::AddUniformVec4( std::string _name, const GLfloat *_data ) {
+ uniforms.resize(uniforms.size()+1);
+ uniforms.back().name = _name;
+ uniforms.back().type = _vec4;
+ uniforms.back().data.resize(4);
+ memcpy(&uniforms.back().data[0], _data, 4*sizeof(GLfloat));
+}
+
+void DrawBatch::AddUniformVec4( std::string _name, const vec4 &_data ) {
+ AddUniformVec4(_name, (const GLfloat*)&_data);
+}
+
+void DrawBatch::SetUniformVec4( std::string _name, const vec4 &_data ) {
+ for(unsigned i=0; i<uniforms.size(); ++i){
+ if(uniforms[i].name == _name){
+ memcpy(&uniforms[i].data[0],
+ (const GLfloat*)_data.entries,
+ 4*sizeof(GLfloat));
+ }
+ }
+}
+
+void DrawBatch::SetTransform(const mat4 &_transform)
+{
+ transform = _transform;
+ inv_transpose_transform = mat3(transform.GetInverseTranspose());
+}