1 /*
   2  * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef HEADLESS
  27 
  28 #import "VertexDataManager.h"
  29 #import <Metal/Metal.h>
  30 
  31 
  32 
  33 static int MAX_PRIMITIVES = 100; //TODO : this needs to be changed to dynamic array of structures to support any number of primitives
  34 
  35 // TODO : all static members should be class members when singleton is implemented
  36 static id<MTLBuffer> VertexBuffer;
  37 static id<MTLBuffer> IndexBuffer;
  38 static unsigned int no_of_vertices = 0;
  39 static unsigned int no_of_indices = 0;
  40 static unsigned int no_of_primitives = 0;
  41 MetalPrimitiveData** AllPrimitives = NULL;
  42 
  43 
  44 void VertexDataManager_init(id<MTLDevice> device) {
  45     // This limited buffer size allocation is for PoC purpose. 
  46     // TODO : Need to implement a logic where we allocate more chunks if needed
  47 
  48     VertexBuffer = [device newBufferWithLength:1024 * 32 options:MTLResourceOptionCPUCacheModeDefault];
  49     IndexBuffer  = [device newBufferWithLength:1024 * 8 options:MTLResourceOptionCPUCacheModeDefault];
  50 
  51     AllPrimitives = (MetalPrimitiveData**) malloc(sizeof(MetalPrimitiveData*) * MAX_PRIMITIVES); //[[NSMutableArray<MetalPrimitiveData*> alloc] init];
  52 }
  53 
  54 void VertexDataManager_addLineVertexData(MetalVertex v1, MetalVertex v2) {
  55 
  56           // Create a structure of MetalPrimitiveData (populate it) and it to the array
  57           MetalPrimitiveData* data = (MetalPrimitiveData*) malloc(sizeof(MetalPrimitiveData));//[[MetalPrimitiveData alloc] init];
  58           data->type = MTLPrimitiveTypeLine;
  59           data->offset_in_index_buffer = (no_of_indices) * sizeof(unsigned short);
  60           data->no_of_indices = 2;
  61           data->primitiveInstances = 1;
  62     
  63     AllPrimitives[no_of_primitives] = data;  
  64           no_of_primitives++;
  65 
  66           // Add v1, v2 to VertexBuffer
  67           addIndex(no_of_vertices);
  68 
  69     addVertex(v1);
  70     
  71     addIndex(no_of_vertices);
  72 
  73     addVertex(v2);
  74 }
  75 
  76 void VertexDataManager_addQuadVertexData(MetalVertex v1, MetalVertex v2, MetalVertex v3, MetalVertex v4) {
  77         
  78     MetalPrimitiveData* data = (MetalPrimitiveData*) malloc(sizeof(MetalPrimitiveData));//[[MetalPrimitiveData alloc] init];
  79           data->type = MTLPrimitiveTypeTriangle;
  80           data->offset_in_index_buffer = (no_of_indices) * sizeof(unsigned short);
  81           data->no_of_indices = 6;
  82           data->primitiveInstances = 2;
  83 
  84           AllPrimitives[no_of_primitives] = data;
  85     no_of_primitives++;
  86 
  87           // Add all 4 vertices to the Vertexbuffer
  88           unsigned int firstVertexNumber = no_of_vertices;
  89 
  90     addVertex(v1);
  91     addVertex(v2);
  92     addVertex(v3);
  93     addVertex(v4);
  94 
  95     /*
  96        v1-------v4
  97        | \      |
  98        |  \     |
  99        |   \    |
 100        |    \   |
 101        |     \  |
 102        |      \ |
 103        |       \|
 104        v2-------v3
 105     */
 106     
 107     // A quad is made up of two triangles
 108     // Order of vertices is important - it is counter-clockwise
 109           // Specify 2 set of triangles using 3 indices each
 110     addIndex(firstVertexNumber);     // v1
 111     addIndex(firstVertexNumber + 1); // v2
 112     addIndex(firstVertexNumber + 2); // v3
 113 
 114     addIndex(firstVertexNumber + 2); // v3
 115     addIndex(firstVertexNumber + 3); // v4
 116     addIndex(firstVertexNumber);     // v1
 117 }
 118 
 119 void addVertex(MetalVertex vert) {
 120     memcpy(VertexBuffer.contents + (no_of_vertices * sizeof(MetalVertex)), &vert, sizeof(MetalVertex));
 121     no_of_vertices++;
 122 }
 123 
 124 void addIndex(unsigned short vertexNum) {
 125         memcpy(IndexBuffer.contents + no_of_indices * sizeof(unsigned short), &vertexNum,  sizeof(unsigned short));
 126         no_of_indices++;
 127 }
 128 
 129 
 130 id<MTLBuffer> VertexDataManager_getVertexBuffer() {
 131         return VertexBuffer;
 132 }
 133 
 134 id<MTLBuffer> VertexDataManager_getIndexBuffer() {
 135         return IndexBuffer;
 136 }
 137 
 138 MetalPrimitiveData** VertexDataManager_getAllPrimitives() {
 139     return AllPrimitives;
 140 }
 141 
 142 unsigned int VertexDataManager_getNoOfPrimitives() {
 143         return no_of_primitives;
 144 }
 145 
 146 void VertexDataManager_freeAllPrimitives() {
 147  
 148     for (int i = 0; i < no_of_primitives; i++) {
 149         free(AllPrimitives[i]);
 150     }
 151 
 152     free(AllPrimitives);
 153 }
 154 
 155 void VertexDataManager_reset(id<MTLDevice> device) {
 156     VertexDataManager_freeAllPrimitives();
 157     VertexBuffer = NULL;
 158     IndexBuffer = NULL;
 159     no_of_vertices = 0;
 160     no_of_indices = 0;
 161     no_of_primitives = 0;
 162     AllPrimitives = NULL;
 163     VertexDataManager_init(device);
 164 }
 165 
 166 #endif /* !HEADLESS */